{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 简单理解两种 Direct RPA 相关能程序实现等价性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 创建时间：2020-08-02"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这篇文档中，我们会讨论基于 Pure-GGA 参考态的 Direct RPA (dRPA) 相关能计算。理论推导着重从类 TD-KS 方程出发，而程序实现会讨论两种 $O(N^6)$ 与一种 $O(N^4)$ 方法。\n",
    "\n",
    "Direct RPA 可以看作是 Rung 5th 的密度泛函方法，其精度一般来说高于一般的杂化泛函 (B3LYP, PBE0 等)，计算复杂度大约为双杂化泛函 (XYG3, B2PLYP 等) 或更低一些，被认为可能对一些近简并体系能较为圆滑地处理。\n",
    "\n",
    "密度泛函的近似着重处理交换相关能。Direct RPA 的交换能一般通过 Exact 交换能 (不准确地说是 Hartree-Fock 交换能) 获得，而相关能的计算相对特殊。几乎所有量子化学软件具有计算 Direct RPA 的能力，但发行版中明确拥有这一特性的软件较少，一般来说有 Ren Xinguo 为代表的 FHI-Aims [^Ren-Scheffler.NJP.2012.14] 与 Furche 为代表的 Turbomole [^Furche-Furche.JCP.2008.129]。在较小的模型体系下，该文档的计算结果与这两个软件的结果作对比与核验。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这篇文档中，既不引用也不加以证明的公式，有 TD-KS (Casida) 方程、Wick 二次量子化算符交换规则、Cauchy-Goursat 积分定理等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib notebook\n",
    "\n",
    "from pyscf import gto, dft, scf, tdscf, df\n",
    "import numpy as np\n",
    "import scipy\n",
    "from scipy.linalg import fractional_matrix_power\n",
    "from functools import partial\n",
    "from matplotlib import pyplot as plt\n",
    "from IPython.display import Image\n",
    "\n",
    "np.set_printoptions(5, linewidth=120, suppress=True)\n",
    "np.einsum = partial(np.einsum, optimize=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "## 分子体系与 PBE 能量计算"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们使用 cc-pVTZ 基组的水分子举例。格点使用 PySCF 的默认格点，即 prune 的氧原子 (75, 302)，氢原子 (50, 302) 格点。该分子实例记在 `mol` 中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pyscf.gto.mole.Mole at 0x7f5480a324f0>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mol = gto.Mole()\n",
    "mol.atom = \"\"\"\n",
    "O  0. 0. 0.\n",
    "H  0. 0. 1.\n",
    "H  0. 1. 0.\n",
    "\"\"\"\n",
    "mol.basis = \"cc-pVTZ\"\n",
    "mol.verbose = 0\n",
    "mol.build()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们在后文会使用到 RI (Resolution of Identity) 方法，因此需要定义 DF (Density Fitting) 基组。我们使用的 DF 基组是 cc-pVTZ-ri。该分子实例记在 `mol_df` 中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pyscf.gto.mole.Mole at 0x7f54b1a98850>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mol_df = mol.copy()\n",
    "mol_df.basis = \"cc-pVTZ-ri\"\n",
    "mol_df.build()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们首先计算分子的 PBE 能量，其目的是得到 PBE 的分子轨道。该计算实例记在 `mf` 中。出于便利，我们使用未经过 DF (Density Fitting) 的自洽场。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-76.36780110085748"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mf = dft.RKS(mol, xc=\"PBE\").run()\n",
    "mf.e_tot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们随后需要定义与分子或方法有关的变量。我们使用 $i, j$ 表示占据分子轨道，$a, b$ 表示非占分子轨道，$p, q, r, s$ 表示全部分子轨道，$\\mu, \\nu, \\kappa, \\lambda$ 表示原子轨道，$P, Q$ 表示 DF 轨道。\n",
    "\n",
    "- `nocc` $n_\\mathrm{occ}$ 占据轨道数\n",
    "\n",
    "- `nvir` $n_\\mathrm{vir}$ 未占轨道数\n",
    "\n",
    "- `nmo` $n_\\mathrm{MO}$ 分子轨道数，等于占据轨道数 `nao` $n_\\mathrm{AO}$\n",
    "\n",
    "- `naux` $n_\\mathrm{aux}$ Density Fitting 基组轨道数 (或者也称辅助基组 Auxiliary)\n",
    "\n",
    "- `so`, `sv`, `sa` 占据、未占、全轨道分割 (用于程序编写)\n",
    "\n",
    "- `eri0_ao` $(\\mu \\nu | \\kappa \\lambda)$ 原子轨道双电子排斥积分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "nocc, nmo, nao = mol.nelec[0], mol.nao, mol.nao\n",
    "naux = mol_df.nao\n",
    "nvir = nmo - nocc\n",
    "so, sv, sa = slice(0, nocc), slice(nocc, nmo), slice(0, nmo)\n",
    "eri0_ao = mol.intor(\"int2e\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "- `e`, `eo`, `ev` $e_{p}$ 全、占据、未占 PBE 轨道能\n",
    "\n",
    "- `C`, `Co`, `Cv` $C_{\\mu p}$ 全、占据、未占 PBE 轨道系数\n",
    "\n",
    "以往的文档中都会对密度矩阵作定义；但这篇文档中会有另一处记号与密度矩阵非常相似，并且通篇不太使用密度矩阵，因此不做定义。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "e, C = mf.mo_energy, mf.mo_coeff\n",
    "eo, ev = e[so], e[sv]\n",
    "Co, Cv = C[:, so], C[:, sv]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "- `eri0_mo` $(pq|rs)$ 分子轨道双电子排斥积分\n",
    "\n",
    "- `eri0_iajb` $(ia|jb)$ 上述张量的占据-非占-占据-非占的分割"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "eri0_mo = np.einsum(\"uvkl, up, vq, kr, ls -> pqrs\", eri0_ao, C, C, C, C)\n",
    "eri0_iajb = eri0_mo[so, sv, so, sv]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "对于 Direct RPA，其矫正能并不是对 PBE 自洽场能直接作矫正，而是如下的形式：\n",
    "\n",
    "$$\n",
    "E^\\mathsf{dRPA}_\\mathrm{tot} = E^\\mathsf{PBE}_\\mathrm{tot} - E^\\mathsf{PBE}_\\mathrm{xc} + E^\\mathsf{exact}_\\mathrm{x} + E^\\mathsf{dRPA}_\\mathrm{c}\n",
    "$$\n",
    "\n",
    "我们首先给出 PBE 交换相关能 `eng_xc` $E^\\mathsf{PBE}_\\mathrm{xc}$："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-9.218732082968408"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ni = dft.numint.NumInt()\n",
    "eng_xc = ni.nr_vxc(mol, mf.grids, \"PBE\", mf.make_rdm1())[1]\n",
    "eng_xc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "以及 Exact 交换能 `eng_exactX` $E^\\mathsf{exact}_\\mathrm{x}$：\n",
    "\n",
    "$$\n",
    "E^\\mathsf{exact}_\\mathrm{x} = - \\sum_{\\mu \\nu \\kappa \\lambda} C_{\\mu i} C_{\\nu i} (\\mu \\kappa | \\nu \\lambda) C_{\\kappa j} C_{\\lambda j}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-8.887856003073837"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eng_exactX = - np.einsum(\"ui, vi, ukvl, kj, lj ->\", Co, Co, eri0_ao, Co, Co)\n",
    "eng_exactX"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "那么 dRPA 中，除了 $E^\\mathsf{dRPA}_\\mathrm{c}$ 之外的部分都是可求的。定义其为 HXX 能量：\n",
    "\n",
    "$$\n",
    "E^\\mathsf{dRPA}_\\mathrm{tot} = E^\\mathsf{HXX} + E^\\mathsf{dRPA}_\\mathrm{c}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-76.03692502096291"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eng_HXX = mf.e_tot - eng_xc + eng_exactX\n",
    "eng_HXX"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "这份文档随后的任务就是求取 $E^\\mathsf{dRPA}_\\mathrm{c}$。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 程序实现：类 TD-KS 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### PySCF 程序实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们可以使用 PySCF 现成的类简单地实现 $E^\\mathsf{dRPA}_\\mathrm{c}$。在 PySCF 中，通过计算 PySCF 所计算的 dRPA 与 dTDA 激发能，并对两者相减求和，就得到了 dRPA 相关能：\n",
    "\n",
    "$$\n",
    "E^\\mathsf{dRPA}_\\mathrm{c} = \\frac{1}{2} \\sum_n (\\omega_n^\\mathsf{dRPA} - \\omega_n^\\mathsf{dTDA}) \\tag{1}\n",
    "$$\n",
    "\n",
    "上式是对下标 $n$ 求和，其中 $n$ 表示基态向上的第 $n$ 个激发态，$\\omega_n^\\mathsf{dRPA}$ 表示 dRPA 激发近似下的第 $n$ 个激发态的激发能；$\\omega_n^\\mathsf{dTDA}$ 类似。\n",
    "\n",
    "但需要留意，PySCF (以及绝大多数量化软件) 的 TD-KS 的解通常只求 20 个以内，但我们原则上需要计算所有的激发能并求和，且最多求取 $n_\\mathrm{occ} \\times n_\\mathrm{vir}$。由于算力在当前体系下不成问题，因此我们就求取最多的激发态能量数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pyscf.tdscf.rks.dRPA at 0x7f547ee55370>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mf_dRPA = tdscf.dRPA(mf)\n",
    "mf_dRPA.nstates = nvir * nocc\n",
    "mf_dRPA.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pyscf.tdscf.rks.dTDA at 0x7f547d1d2c70>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mf_dTDA = tdscf.dTDA(mf)\n",
    "mf_dTDA.nstates = nvir * nocc\n",
    "mf_dTDA.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.4313792211677736"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eng_dRPA_tdks = 0.5 * (mf_dRPA.e - mf_dTDA.e).sum()\n",
    "eng_dRPA_tdks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "既然已经求出相关能，那么我们就可以求出总的 dRPA 能量 $E^\\mathsf{dRPA}_\\mathrm{tot}$："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-76.46830424213069"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eng_dRPA_tot = eng_HXX + eng_dRPA_tdks\n",
    "eng_dRPA_tot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "在这一段的最后，我们看一下每个激发态对相关能的贡献："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "/* Put everything inside the global mpl namespace */\n",
       "window.mpl = {};\n",
       "\n",
       "\n",
       "mpl.get_websocket_type = function() {\n",
       "    if (typeof(WebSocket) !== 'undefined') {\n",
       "        return WebSocket;\n",
       "    } else if (typeof(MozWebSocket) !== 'undefined') {\n",
       "        return MozWebSocket;\n",
       "    } else {\n",
       "        alert('Your browser does not have WebSocket support. ' +\n",
       "              'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
       "              'Firefox 4 and 5 are also supported but you ' +\n",
       "              'have to enable WebSockets in about:config.');\n",
       "    };\n",
       "}\n",
       "\n",
       "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
       "    this.id = figure_id;\n",
       "\n",
       "    this.ws = websocket;\n",
       "\n",
       "    this.supports_binary = (this.ws.binaryType != undefined);\n",
       "\n",
       "    if (!this.supports_binary) {\n",
       "        var warnings = document.getElementById(\"mpl-warnings\");\n",
       "        if (warnings) {\n",
       "            warnings.style.display = 'block';\n",
       "            warnings.textContent = (\n",
       "                \"This browser does not support binary websocket messages. \" +\n",
       "                    \"Performance may be slow.\");\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.imageObj = new Image();\n",
       "\n",
       "    this.context = undefined;\n",
       "    this.message = undefined;\n",
       "    this.canvas = undefined;\n",
       "    this.rubberband_canvas = undefined;\n",
       "    this.rubberband_context = undefined;\n",
       "    this.format_dropdown = undefined;\n",
       "\n",
       "    this.image_mode = 'full';\n",
       "\n",
       "    this.root = $('<div/>');\n",
       "    this._root_extra_style(this.root)\n",
       "    this.root.attr('style', 'display: inline-block');\n",
       "\n",
       "    $(parent_element).append(this.root);\n",
       "\n",
       "    this._init_header(this);\n",
       "    this._init_canvas(this);\n",
       "    this._init_toolbar(this);\n",
       "\n",
       "    var fig = this;\n",
       "\n",
       "    this.waiting = false;\n",
       "\n",
       "    this.ws.onopen =  function () {\n",
       "            fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
       "            fig.send_message(\"send_image_mode\", {});\n",
       "            if (mpl.ratio != 1) {\n",
       "                fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
       "            }\n",
       "            fig.send_message(\"refresh\", {});\n",
       "        }\n",
       "\n",
       "    this.imageObj.onload = function() {\n",
       "            if (fig.image_mode == 'full') {\n",
       "                // Full images could contain transparency (where diff images\n",
       "                // almost always do), so we need to clear the canvas so that\n",
       "                // there is no ghosting.\n",
       "                fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
       "            }\n",
       "            fig.context.drawImage(fig.imageObj, 0, 0);\n",
       "        };\n",
       "\n",
       "    this.imageObj.onunload = function() {\n",
       "        fig.ws.close();\n",
       "    }\n",
       "\n",
       "    this.ws.onmessage = this._make_on_message_function(this);\n",
       "\n",
       "    this.ondownload = ondownload;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_header = function() {\n",
       "    var titlebar = $(\n",
       "        '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
       "        'ui-helper-clearfix\"/>');\n",
       "    var titletext = $(\n",
       "        '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
       "        'text-align: center; padding: 3px;\"/>');\n",
       "    titlebar.append(titletext)\n",
       "    this.root.append(titlebar);\n",
       "    this.header = titletext[0];\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
       "\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
       "\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_canvas = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var canvas_div = $('<div/>');\n",
       "\n",
       "    canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
       "\n",
       "    function canvas_keyboard_event(event) {\n",
       "        return fig.key_event(event, event['data']);\n",
       "    }\n",
       "\n",
       "    canvas_div.keydown('key_press', canvas_keyboard_event);\n",
       "    canvas_div.keyup('key_release', canvas_keyboard_event);\n",
       "    this.canvas_div = canvas_div\n",
       "    this._canvas_extra_style(canvas_div)\n",
       "    this.root.append(canvas_div);\n",
       "\n",
       "    var canvas = $('<canvas/>');\n",
       "    canvas.addClass('mpl-canvas');\n",
       "    canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
       "\n",
       "    this.canvas = canvas[0];\n",
       "    this.context = canvas[0].getContext(\"2d\");\n",
       "\n",
       "    var backingStore = this.context.backingStorePixelRatio ||\n",
       "\tthis.context.webkitBackingStorePixelRatio ||\n",
       "\tthis.context.mozBackingStorePixelRatio ||\n",
       "\tthis.context.msBackingStorePixelRatio ||\n",
       "\tthis.context.oBackingStorePixelRatio ||\n",
       "\tthis.context.backingStorePixelRatio || 1;\n",
       "\n",
       "    mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
       "\n",
       "    var rubberband = $('<canvas/>');\n",
       "    rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
       "\n",
       "    var pass_mouse_events = true;\n",
       "\n",
       "    canvas_div.resizable({\n",
       "        start: function(event, ui) {\n",
       "            pass_mouse_events = false;\n",
       "        },\n",
       "        resize: function(event, ui) {\n",
       "            fig.request_resize(ui.size.width, ui.size.height);\n",
       "        },\n",
       "        stop: function(event, ui) {\n",
       "            pass_mouse_events = true;\n",
       "            fig.request_resize(ui.size.width, ui.size.height);\n",
       "        },\n",
       "    });\n",
       "\n",
       "    function mouse_event_fn(event) {\n",
       "        if (pass_mouse_events)\n",
       "            return fig.mouse_event(event, event['data']);\n",
       "    }\n",
       "\n",
       "    rubberband.mousedown('button_press', mouse_event_fn);\n",
       "    rubberband.mouseup('button_release', mouse_event_fn);\n",
       "    // Throttle sequential mouse events to 1 every 20ms.\n",
       "    rubberband.mousemove('motion_notify', mouse_event_fn);\n",
       "\n",
       "    rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
       "    rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
       "\n",
       "    canvas_div.on(\"wheel\", function (event) {\n",
       "        event = event.originalEvent;\n",
       "        event['data'] = 'scroll'\n",
       "        if (event.deltaY < 0) {\n",
       "            event.step = 1;\n",
       "        } else {\n",
       "            event.step = -1;\n",
       "        }\n",
       "        mouse_event_fn(event);\n",
       "    });\n",
       "\n",
       "    canvas_div.append(canvas);\n",
       "    canvas_div.append(rubberband);\n",
       "\n",
       "    this.rubberband = rubberband;\n",
       "    this.rubberband_canvas = rubberband[0];\n",
       "    this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
       "    this.rubberband_context.strokeStyle = \"#000000\";\n",
       "\n",
       "    this._resize_canvas = function(width, height) {\n",
       "        // Keep the size of the canvas, canvas container, and rubber band\n",
       "        // canvas in synch.\n",
       "        canvas_div.css('width', width)\n",
       "        canvas_div.css('height', height)\n",
       "\n",
       "        canvas.attr('width', width * mpl.ratio);\n",
       "        canvas.attr('height', height * mpl.ratio);\n",
       "        canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
       "\n",
       "        rubberband.attr('width', width);\n",
       "        rubberband.attr('height', height);\n",
       "    }\n",
       "\n",
       "    // Set the figure to an initial 600x600px, this will subsequently be updated\n",
       "    // upon first draw.\n",
       "    this._resize_canvas(600, 600);\n",
       "\n",
       "    // Disable right mouse context menu.\n",
       "    $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
       "        return false;\n",
       "    });\n",
       "\n",
       "    function set_focus () {\n",
       "        canvas.focus();\n",
       "        canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    window.setTimeout(set_focus, 100);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var nav_element = $('<div/>');\n",
       "    nav_element.attr('style', 'width: 100%');\n",
       "    this.root.append(nav_element);\n",
       "\n",
       "    // Define a callback function for later on.\n",
       "    function toolbar_event(event) {\n",
       "        return fig.toolbar_button_onclick(event['data']);\n",
       "    }\n",
       "    function toolbar_mouse_event(event) {\n",
       "        return fig.toolbar_button_onmouseover(event['data']);\n",
       "    }\n",
       "\n",
       "    for(var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            // put a spacer in here.\n",
       "            continue;\n",
       "        }\n",
       "        var button = $('<button/>');\n",
       "        button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
       "                        'ui-button-icon-only');\n",
       "        button.attr('role', 'button');\n",
       "        button.attr('aria-disabled', 'false');\n",
       "        button.click(method_name, toolbar_event);\n",
       "        button.mouseover(tooltip, toolbar_mouse_event);\n",
       "\n",
       "        var icon_img = $('<span/>');\n",
       "        icon_img.addClass('ui-button-icon-primary ui-icon');\n",
       "        icon_img.addClass(image);\n",
       "        icon_img.addClass('ui-corner-all');\n",
       "\n",
       "        var tooltip_span = $('<span/>');\n",
       "        tooltip_span.addClass('ui-button-text');\n",
       "        tooltip_span.html(tooltip);\n",
       "\n",
       "        button.append(icon_img);\n",
       "        button.append(tooltip_span);\n",
       "\n",
       "        nav_element.append(button);\n",
       "    }\n",
       "\n",
       "    var fmt_picker_span = $('<span/>');\n",
       "\n",
       "    var fmt_picker = $('<select/>');\n",
       "    fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
       "    fmt_picker_span.append(fmt_picker);\n",
       "    nav_element.append(fmt_picker_span);\n",
       "    this.format_dropdown = fmt_picker[0];\n",
       "\n",
       "    for (var ind in mpl.extensions) {\n",
       "        var fmt = mpl.extensions[ind];\n",
       "        var option = $(\n",
       "            '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
       "        fmt_picker.append(option);\n",
       "    }\n",
       "\n",
       "    // Add hover states to the ui-buttons\n",
       "    $( \".ui-button\" ).hover(\n",
       "        function() { $(this).addClass(\"ui-state-hover\");},\n",
       "        function() { $(this).removeClass(\"ui-state-hover\");}\n",
       "    );\n",
       "\n",
       "    var status_bar = $('<span class=\"mpl-message\"/>');\n",
       "    nav_element.append(status_bar);\n",
       "    this.message = status_bar[0];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
       "    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
       "    // which will in turn request a refresh of the image.\n",
       "    this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.send_message = function(type, properties) {\n",
       "    properties['type'] = type;\n",
       "    properties['figure_id'] = this.id;\n",
       "    this.ws.send(JSON.stringify(properties));\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.send_draw_message = function() {\n",
       "    if (!this.waiting) {\n",
       "        this.waiting = true;\n",
       "        this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
       "    var format_dropdown = fig.format_dropdown;\n",
       "    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
       "    fig.ondownload(fig, format);\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
       "    var size = msg['size'];\n",
       "    if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
       "        fig._resize_canvas(size[0], size[1]);\n",
       "        fig.send_message(\"refresh\", {});\n",
       "    };\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
       "    var x0 = msg['x0'] / mpl.ratio;\n",
       "    var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
       "    var x1 = msg['x1'] / mpl.ratio;\n",
       "    var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
       "    x0 = Math.floor(x0) + 0.5;\n",
       "    y0 = Math.floor(y0) + 0.5;\n",
       "    x1 = Math.floor(x1) + 0.5;\n",
       "    y1 = Math.floor(y1) + 0.5;\n",
       "    var min_x = Math.min(x0, x1);\n",
       "    var min_y = Math.min(y0, y1);\n",
       "    var width = Math.abs(x1 - x0);\n",
       "    var height = Math.abs(y1 - y0);\n",
       "\n",
       "    fig.rubberband_context.clearRect(\n",
       "        0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
       "\n",
       "    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
       "    // Updates the figure title.\n",
       "    fig.header.textContent = msg['label'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
       "    var cursor = msg['cursor'];\n",
       "    switch(cursor)\n",
       "    {\n",
       "    case 0:\n",
       "        cursor = 'pointer';\n",
       "        break;\n",
       "    case 1:\n",
       "        cursor = 'default';\n",
       "        break;\n",
       "    case 2:\n",
       "        cursor = 'crosshair';\n",
       "        break;\n",
       "    case 3:\n",
       "        cursor = 'move';\n",
       "        break;\n",
       "    }\n",
       "    fig.rubberband_canvas.style.cursor = cursor;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
       "    fig.message.textContent = msg['message'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
       "    // Request the server to send over a new figure.\n",
       "    fig.send_draw_message();\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
       "    fig.image_mode = msg['mode'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function() {\n",
       "    // Called whenever the canvas gets updated.\n",
       "    this.send_message(\"ack\", {});\n",
       "}\n",
       "\n",
       "// A function to construct a web socket function for onmessage handling.\n",
       "// Called in the figure constructor.\n",
       "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
       "    return function socket_on_message(evt) {\n",
       "        if (evt.data instanceof Blob) {\n",
       "            /* FIXME: We get \"Resource interpreted as Image but\n",
       "             * transferred with MIME type text/plain:\" errors on\n",
       "             * Chrome.  But how to set the MIME type?  It doesn't seem\n",
       "             * to be part of the websocket stream */\n",
       "            evt.data.type = \"image/png\";\n",
       "\n",
       "            /* Free the memory for the previous frames */\n",
       "            if (fig.imageObj.src) {\n",
       "                (window.URL || window.webkitURL).revokeObjectURL(\n",
       "                    fig.imageObj.src);\n",
       "            }\n",
       "\n",
       "            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
       "                evt.data);\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "        else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
       "            fig.imageObj.src = evt.data;\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        var msg = JSON.parse(evt.data);\n",
       "        var msg_type = msg['type'];\n",
       "\n",
       "        // Call the  \"handle_{type}\" callback, which takes\n",
       "        // the figure and JSON message as its only arguments.\n",
       "        try {\n",
       "            var callback = fig[\"handle_\" + msg_type];\n",
       "        } catch (e) {\n",
       "            console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        if (callback) {\n",
       "            try {\n",
       "                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
       "                callback(fig, msg);\n",
       "            } catch (e) {\n",
       "                console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
       "            }\n",
       "        }\n",
       "    };\n",
       "}\n",
       "\n",
       "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
       "mpl.findpos = function(e) {\n",
       "    //this section is from http://www.quirksmode.org/js/events_properties.html\n",
       "    var targ;\n",
       "    if (!e)\n",
       "        e = window.event;\n",
       "    if (e.target)\n",
       "        targ = e.target;\n",
       "    else if (e.srcElement)\n",
       "        targ = e.srcElement;\n",
       "    if (targ.nodeType == 3) // defeat Safari bug\n",
       "        targ = targ.parentNode;\n",
       "\n",
       "    // jQuery normalizes the pageX and pageY\n",
       "    // pageX,Y are the mouse positions relative to the document\n",
       "    // offset() returns the position of the element relative to the document\n",
       "    var x = e.pageX - $(targ).offset().left;\n",
       "    var y = e.pageY - $(targ).offset().top;\n",
       "\n",
       "    return {\"x\": x, \"y\": y};\n",
       "};\n",
       "\n",
       "/*\n",
       " * return a copy of an object with only non-object keys\n",
       " * we need this to avoid circular references\n",
       " * http://stackoverflow.com/a/24161582/3208463\n",
       " */\n",
       "function simpleKeys (original) {\n",
       "  return Object.keys(original).reduce(function (obj, key) {\n",
       "    if (typeof original[key] !== 'object')\n",
       "        obj[key] = original[key]\n",
       "    return obj;\n",
       "  }, {});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.mouse_event = function(event, name) {\n",
       "    var canvas_pos = mpl.findpos(event)\n",
       "\n",
       "    if (name === 'button_press')\n",
       "    {\n",
       "        this.canvas.focus();\n",
       "        this.canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    var x = canvas_pos.x * mpl.ratio;\n",
       "    var y = canvas_pos.y * mpl.ratio;\n",
       "\n",
       "    this.send_message(name, {x: x, y: y, button: event.button,\n",
       "                             step: event.step,\n",
       "                             guiEvent: simpleKeys(event)});\n",
       "\n",
       "    /* This prevents the web browser from automatically changing to\n",
       "     * the text insertion cursor when the button is pressed.  We want\n",
       "     * to control all of the cursor setting manually through the\n",
       "     * 'cursor' event from matplotlib */\n",
       "    event.preventDefault();\n",
       "    return false;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
       "    // Handle any extra behaviour associated with a key event\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.key_event = function(event, name) {\n",
       "\n",
       "    // Prevent repeat events\n",
       "    if (name == 'key_press')\n",
       "    {\n",
       "        if (event.which === this._key)\n",
       "            return;\n",
       "        else\n",
       "            this._key = event.which;\n",
       "    }\n",
       "    if (name == 'key_release')\n",
       "        this._key = null;\n",
       "\n",
       "    var value = '';\n",
       "    if (event.ctrlKey && event.which != 17)\n",
       "        value += \"ctrl+\";\n",
       "    if (event.altKey && event.which != 18)\n",
       "        value += \"alt+\";\n",
       "    if (event.shiftKey && event.which != 16)\n",
       "        value += \"shift+\";\n",
       "\n",
       "    value += 'k';\n",
       "    value += event.which.toString();\n",
       "\n",
       "    this._key_event_extra(event, name);\n",
       "\n",
       "    this.send_message(name, {key: value,\n",
       "                             guiEvent: simpleKeys(event)});\n",
       "    return false;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
       "    if (name == 'download') {\n",
       "        this.handle_save(this, null);\n",
       "    } else {\n",
       "        this.send_message(\"toolbar_button\", {name: name});\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
       "    this.message.textContent = tooltip;\n",
       "};\n",
       "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
       "\n",
       "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
       "\n",
       "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
       "    // Create a \"websocket\"-like object which calls the given IPython comm\n",
       "    // object with the appropriate methods. Currently this is a non binary\n",
       "    // socket, so there is still some room for performance tuning.\n",
       "    var ws = {};\n",
       "\n",
       "    ws.close = function() {\n",
       "        comm.close()\n",
       "    };\n",
       "    ws.send = function(m) {\n",
       "        //console.log('sending', m);\n",
       "        comm.send(m);\n",
       "    };\n",
       "    // Register the callback with on_msg.\n",
       "    comm.on_msg(function(msg) {\n",
       "        //console.log('receiving', msg['content']['data'], msg);\n",
       "        // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
       "        ws.onmessage(msg['content']['data'])\n",
       "    });\n",
       "    return ws;\n",
       "}\n",
       "\n",
       "mpl.mpl_figure_comm = function(comm, msg) {\n",
       "    // This is the function which gets called when the mpl process\n",
       "    // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
       "\n",
       "    var id = msg.content.data.id;\n",
       "    // Get hold of the div created by the display call when the Comm\n",
       "    // socket was opened in Python.\n",
       "    var element = $(\"#\" + id);\n",
       "    var ws_proxy = comm_websocket_adapter(comm)\n",
       "\n",
       "    function ondownload(figure, format) {\n",
       "        window.open(figure.imageObj.src);\n",
       "    }\n",
       "\n",
       "    var fig = new mpl.figure(id, ws_proxy,\n",
       "                           ondownload,\n",
       "                           element.get(0));\n",
       "\n",
       "    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
       "    // web socket which is closed, not our websocket->open comm proxy.\n",
       "    ws_proxy.onopen();\n",
       "\n",
       "    fig.parent_element = element.get(0);\n",
       "    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
       "    if (!fig.cell_info) {\n",
       "        console.error(\"Failed to find cell for figure\", id, fig);\n",
       "        return;\n",
       "    }\n",
       "\n",
       "    var output_index = fig.cell_info[2]\n",
       "    var cell = fig.cell_info[0];\n",
       "\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
       "    var width = fig.canvas.width/mpl.ratio\n",
       "    fig.root.unbind('remove')\n",
       "\n",
       "    // Update the output cell to use the data from the current canvas.\n",
       "    fig.push_to_output();\n",
       "    var dataURL = fig.canvas.toDataURL();\n",
       "    // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
       "    // the notebook keyboard shortcuts fail.\n",
       "    IPython.keyboard_manager.enable()\n",
       "    $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
       "    fig.close_ws(fig, msg);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.close_ws = function(fig, msg){\n",
       "    fig.send_message('closing', msg);\n",
       "    // fig.ws.close()\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
       "    // Turn the data on the canvas into data in the output cell.\n",
       "    var width = this.canvas.width/mpl.ratio\n",
       "    var dataURL = this.canvas.toDataURL();\n",
       "    this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function() {\n",
       "    // Tell IPython that the notebook contents must change.\n",
       "    IPython.notebook.set_dirty(true);\n",
       "    this.send_message(\"ack\", {});\n",
       "    var fig = this;\n",
       "    // Wait a second, then push the new image to the DOM so\n",
       "    // that it is saved nicely (might be nice to debounce this).\n",
       "    setTimeout(function () { fig.push_to_output() }, 1000);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var nav_element = $('<div/>');\n",
       "    nav_element.attr('style', 'width: 100%');\n",
       "    this.root.append(nav_element);\n",
       "\n",
       "    // Define a callback function for later on.\n",
       "    function toolbar_event(event) {\n",
       "        return fig.toolbar_button_onclick(event['data']);\n",
       "    }\n",
       "    function toolbar_mouse_event(event) {\n",
       "        return fig.toolbar_button_onmouseover(event['data']);\n",
       "    }\n",
       "\n",
       "    for(var toolbar_ind in mpl.toolbar_items){\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) { continue; };\n",
       "\n",
       "        var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
       "        button.click(method_name, toolbar_event);\n",
       "        button.mouseover(tooltip, toolbar_mouse_event);\n",
       "        nav_element.append(button);\n",
       "    }\n",
       "\n",
       "    // Add the status bar.\n",
       "    var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
       "    nav_element.append(status_bar);\n",
       "    this.message = status_bar[0];\n",
       "\n",
       "    // Add the close button to the window.\n",
       "    var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
       "    var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
       "    button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
       "    button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
       "    buttongrp.append(button);\n",
       "    var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
       "    titlebar.prepend(buttongrp);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function(el){\n",
       "    var fig = this\n",
       "    el.on(\"remove\", function(){\n",
       "\tfig.close_ws(fig, {});\n",
       "    });\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function(el){\n",
       "    // this is important to make the div 'focusable\n",
       "    el.attr('tabindex', 0)\n",
       "    // reach out to IPython and tell the keyboard manager to turn it's self\n",
       "    // off when our div gets focus\n",
       "\n",
       "    // location in version 3\n",
       "    if (IPython.notebook.keyboard_manager) {\n",
       "        IPython.notebook.keyboard_manager.register_events(el);\n",
       "    }\n",
       "    else {\n",
       "        // location in version 2\n",
       "        IPython.keyboard_manager.register_events(el);\n",
       "    }\n",
       "\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
       "    var manager = IPython.notebook.keyboard_manager;\n",
       "    if (!manager)\n",
       "        manager = IPython.keyboard_manager;\n",
       "\n",
       "    // Check for shift+enter\n",
       "    if (event.shiftKey && event.which == 13) {\n",
       "        this.canvas_div.blur();\n",
       "        // select the cell after this one\n",
       "        var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
       "        IPython.notebook.select(index + 1);\n",
       "    }\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
       "    fig.ondownload(fig, null);\n",
       "}\n",
       "\n",
       "\n",
       "mpl.find_output_cell = function(html_output) {\n",
       "    // Return the cell and output element which can be found *uniquely* in the notebook.\n",
       "    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
       "    // IPython event is triggered only after the cells have been serialised, which for\n",
       "    // our purposes (turning an active figure into a static one), is too late.\n",
       "    var cells = IPython.notebook.get_cells();\n",
       "    var ncells = cells.length;\n",
       "    for (var i=0; i<ncells; i++) {\n",
       "        var cell = cells[i];\n",
       "        if (cell.cell_type === 'code'){\n",
       "            for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
       "                var data = cell.output_area.outputs[j];\n",
       "                if (data.data) {\n",
       "                    // IPython >= 3 moved mimebundle to data attribute of output\n",
       "                    data = data.data;\n",
       "                }\n",
       "                if (data['text/html'] == html_output) {\n",
       "                    return [cell, data, j];\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "// Register the function which deals with the matplotlib target/channel.\n",
       "// The kernel may be null if the page has been refreshed.\n",
       "if (IPython.notebook.kernel != null) {\n",
       "    IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
       "}\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"\" width=\"800\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(figsize=(8, 3))\n",
    "ax.plot(np.arange(nvir * nocc), 0.5 * (mf_dRPA.e - mf_dTDA.e))\n",
    "ax.set_xlabel(\"Excite States $n$\")\n",
    "ax.set_ylabel(\"Contribution to $E^\\mathsf{dRPA}_\\mathrm{c}$ / a.u.\")\n",
    "fig.tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "从这张图上，尽管能看到前若干个态的相关能贡献较大，但并不能简单地认为后几个态的贡献较小以至于能忽略。因此，我们必须计算所有 PySCF 中所定义的 dRPA 与 dTDA 激发能，才能得到相对来说精确的总 dRPA 相关矫正能。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### PySCF 的 dRPA 与 dTDA 激发能"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "在 PySCF 中，dRPA 能量是通过下述方程获得。首先，我们定义 dRPA 的激发与退激发张量：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "A_{ia, jb}^\\mathsf{dRPA} &= - (\\varepsilon_i - \\varepsilon_a) \\delta_{ij} \\delta_{ab} + 2 (ia|jb) \\\\\n",
    "B_{ia, jb}^\\mathsf{dRPA} &= 2 (ia|jb) \\tag{2}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "随后求解下述本征问题：\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\begin{pmatrix} \\mathbf{A}^\\mathsf{dRPA} & \\mathbf{B}^\\mathsf{dRPA} \\\\ - \\mathbf{B}^\\mathsf{dRPA} & - \\mathbf{A}^\\mathsf{dRPA} \\end{pmatrix}\n",
    "\\begin{pmatrix} \\mathbf{X}_n \\\\ \\mathbf{Y}_n \\end{pmatrix}\n",
    "= \\pm \\omega_n^\\mathsf{dRPA} \\begin{pmatrix} \\mathbf{X}_n \\\\ \\mathbf{Y}_n \\end{pmatrix} \\tag{3}\n",
    "\\end{equation}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们首先定义 dRPA 的 `A_dRPA` $A_{ia, jb}^\\mathsf{dRPA}$ 与 `B_dRPA` $B_{ia, jb}^\\mathsf{dRPA}$，它们尽管是以张量形式定义，但实际计算时使用 $(n_\\mathrm{occ} n_\\mathrm{vir}, n_\\mathrm{occ} n_\\mathrm{vir})$ 维度的矩阵来表达。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "delta_ij, delta_ab = np.eye(nocc), np.eye(nvir)\n",
    "A_dRPA = (\n",
    "    np.einsum(\"ia, ij, ab -> iajb\", - eo[:, None] + ev[None, :], delta_ij, delta_ab)\n",
    "    + 2 * eri0_iajb)\n",
    "B_dRPA = 2 * eri0_iajb\n",
    "A_dRPA, B_dRPA = A_dRPA.reshape(nocc*nvir, nocc*nvir), B_dRPA.reshape(nocc*nvir, nocc*nvir)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "该本征问题会求出正负对应的激发能。我们只需要求取其正激发能 $\\omega_n^\\mathsf{dRPA}$ 部分即可。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "AB_dRPA = np.block([\n",
    "    [ A_dRPA,  B_dRPA],\n",
    "    [-B_dRPA, -A_dRPA],\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "计算得到的激发能将从小到大储存到 `e_dRPA` 中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "e_dRPA = np.linalg.eig(AB_dRPA)[0]\n",
    "e_dRPA.sort()\n",
    "e_dRPA = e_dRPA[nocc*nvir:]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "该激发能可以与 PySCF 所的到的激发能对照："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.allclose(e_dRPA, mf_dRPA.e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "同样地，对 dTDA 激发也能作相应的验证。与 dRPA 激发的区别在于激发与退激发张量构造上有所不同："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "$$\n",
    "\\begin{align}\n",
    "A_{ia, jb}^\\mathsf{dTDA} &= - (\\varepsilon_i - \\varepsilon_a) \\delta_{ij} \\delta_{ab} + 2 (ia|jb) = A_{ia, jb}^\\mathsf{dRPA} \\\\\n",
    "B_{ia, jb}^\\mathsf{dTDA} &= 0\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "尽管其本征问题从构造上与 dRPA 激发可以一致，但也可以简化为\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\mathbf{A}^\\mathsf{dTDA} \\mathbf{X}_n = \\omega^\\mathsf{dTDA}_n \\mathbf{X}_n \\tag{4}\n",
    "\\end{equation}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "A_dTDA = A_dRPA\n",
    "e_dTDA = np.linalg.eig(A_dRPA)[0]\n",
    "e_dTDA.sort()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.allclose(e_dTDA, mf_dTDA.e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 程序实现：$O(N^6)$ 直接实现方式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 程序实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "从公式表达上，类似 TD-KS 方程的解并不是比较方便的写法。一种比较早期的实现方式在 Furche 的文章 [^Furche-Furche.PRB.2001.64] 中提及，但比较友好的表达公式在 Eshuis, Furche et al. [^Eshuis-Furche.TCA.2012.131] (eq.76)。其实现方式是"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "$$\n",
    "\\begin{align}\n",
    "\\mathbf{M} &= (\\mathbf{A}^\\mathsf{dRPA} - \\mathbf{B}^\\mathsf{dRPA})^{1/2} (\\mathbf{A}^\\mathsf{dRPA} + \\mathbf{B}^\\mathsf{dRPA}) (\\mathbf{A}^\\mathsf{dRPA} - \\mathbf{B}^\\mathsf{dRPA})^{1/2} \\\\\n",
    "E^\\mathsf{dRPA}_\\mathrm{c} &= \\frac{1}{2} \\mathrm{tr} (\\mathbf{M}^{1/2} - \\mathbf{A}^\\mathsf{dTDA}) \\tag{5}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "其程序实现也非常方便。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.4313792211663592"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "AmB_1p2 = fractional_matrix_power(A_dRPA - B_dRPA, 0.5)\n",
    "M = AmB_1p2 @ (A_dRPA + B_dRPA) @ AmB_1p2\n",
    "eng_dRPA_direct = 0.5 * np.trace(fractional_matrix_power(M, 0.5) - A_dTDA)\n",
    "eng_dRPA_direct"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "之所以说是 $O(N^6)$ 计算复杂度，是因为其中使用到了矩阵的分数幂次与乘积；而矩阵的长与宽都是 $n_\\mathrm{occ} n_\\mathrm{vir}$，因此其计算量复杂度是 $O(n_\\mathrm{occ}^3 n_\\mathrm{vir}^3)$ 的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 与类 TD-KS 实现等价性的数学说明"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "首先，我们作一些线性代数的基础知识补充。我们先定义两个 5 维度任意张量 `X`, `Y` $\\mathbf{X}, \\mathbf{Y}$，来表述问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "np.random.seed(0)\n",
    "X = np.random.randn(5, 5)\n",
    "Y = np.random.randn(5, 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "**(1)** 矩阵迹的和可以直接作拆分：\n",
    "\n",
    "$$\n",
    "\\mathrm{tr} (\\mathbf{X} + \\mathbf{Y}) = \\mathrm{tr} (\\mathbf{X}) + \\mathrm{tr} (\\mathbf{Y})\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.allclose((X + Y).trace(), X.trace() + Y.trace())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "**(2)** 交换律：\n",
    "\n",
    "$$\n",
    "\\mathrm{tr} (\\mathbf{X} \\mathbf{Y}) = \\mathrm{tr} (\\mathbf{Y} \\mathbf{X})\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.allclose((X @ Y).trace(), (Y @ X).trace())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "**(2)** 矩阵的迹等于其本征值的和：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\mathbf{X} \\boldsymbol{f}_n &= \\omega_n \\boldsymbol{f}_n \\\\\n",
    "\\mathrm{tr} (\\mathbf{X}) &= \\sum_n \\omega_n\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eig, F = np.linalg.eig(X)\n",
    "np.allclose(X.trace(), eig.sum())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "说明如下。如果我们定义矩阵 `F` $\\mathbf{F}$ 为列向量 $\\{ \\boldsymbol{f}_n \\}$ 的并，以及 `O` $\\mathbf{\\Omega}$ 是以本征值 `w` $\\{ \\omega_n \\}$ 为对角元的对角矩阵，那么\n",
    "\n",
    "$$\n",
    "\\mathbf{X} \\mathbf{F} = \\mathbf{F} \\mathbf{\\Omega}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "O = np.diag(eig)\n",
    "np.allclose(X @ F, F @ O)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此，\n",
    "\n",
    "$$\n",
    "\\sum_n \\omega_n \\equiv \\sum_n \\Omega_{nn} = \\mathrm{tr} (\\mathbf{\\Omega}) = \\mathrm{tr} (\\mathbf{F}^{-1} \\mathbf{X} \\mathbf{F}) = \\mathrm{tr} (\\mathbf{F}^{-1} \\mathbf{F} \\mathbf{X}) = \\mathrm{tr} (\\mathbf{X})\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "有上述的基础知识后，我们可以说明式 (5) 的 $O(N^6)$ 的公式表达与式 (1) 的类 TD-KS 方程实现是等价的。\n",
    "\n",
    "**(a)** $\\omega_n^\\mathsf{dRPA}$\n",
    "\n",
    "我们先回顾式 (3) 所导出的 dRPA 激发能：\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix} \\mathbf{A}^\\mathsf{dRPA} & \\mathbf{B}^\\mathsf{dRPA} \\\\ - \\mathbf{B}^\\mathsf{dRPA} & - \\mathbf{A}^\\mathsf{dRPA} \\end{pmatrix}\n",
    "\\begin{pmatrix} \\mathbf{X}_n \\\\ \\mathbf{Y}_n \\end{pmatrix}\n",
    "= \\pm \\omega_n^\\mathsf{dRPA} \\begin{pmatrix} \\mathbf{X}_n \\\\ \\mathbf{Y}_n \\end{pmatrix}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "从矩阵转换为方程则表达为 (我们只考虑正激发能结果，因此去除上式的正负号 $\\pm$)：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\mathbf{A}^\\mathsf{dRPA} \\mathbf{X}_n + \\mathbf{B}^\\mathsf{dRPA} \\mathbf{Y}_n &= \\omega_n^\\mathsf{dRPA} \\mathbf{X}_n \\\\\n",
    "\\mathbf{B}^\\mathsf{dRPA} \\mathbf{X}_n + \\mathbf{A}^\\mathsf{dRPA} \\mathbf{Y}_n &= - \\omega_n^\\mathsf{dRPA} \\mathbf{Y}_n\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "将上两式作加减法，得到\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "(\\mathbf{A}^\\mathsf{dRPA} + \\mathbf{B}^\\mathsf{dRPA}) (\\mathbf{X}_n + \\mathbf{Y}_n) &= \\omega_n^\\mathsf{dRPA} (\\mathbf{X}_n - \\mathbf{Y}_n) \\\\\n",
    "(\\mathbf{A}^\\mathsf{dRPA} - \\mathbf{B}^\\mathsf{dRPA}) (\\mathbf{X}_n - \\mathbf{Y}_n) &= \\omega_n^\\mathsf{dRPA} (\\mathbf{X}_n + \\mathbf{Y}_n)\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "将上两式左右相乘，可以得到\n",
    "\n",
    "$$\n",
    "\\big( (\\mathbf{A}^\\mathsf{dRPA} + \\mathbf{B}^\\mathsf{dRPA}) (\\mathbf{A}^\\mathsf{dRPA} - \\mathbf{B}^\\mathsf{dRPA}) \\big) (\\mathbf{X}_n^2 - \\mathbf{Y}_n^2) = (\\omega_n^\\mathsf{dRPA})^2 (\\mathbf{X}_n^2 - \\mathbf{Y}_n^2)\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "对上式左右开根号，得到\n",
    "\n",
    "$$\n",
    "\\big( (\\mathbf{A}^\\mathsf{dRPA} + \\mathbf{B}^\\mathsf{dRPA}) (\\mathbf{A}^\\mathsf{dRPA} - \\mathbf{B}^\\mathsf{dRPA}) \\big)^{1/2} (\\mathbf{X}_n^2 - \\mathbf{Y}_n^2)^{1/2} = \\omega_n^\\mathsf{dRPA} (\\mathbf{X}_n^2 - \\mathbf{Y}_n^2)^{1/2}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "由于矩阵的迹等于其本征值的和，因此\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\sum_{n} \\omega_n^\\mathsf{dRPA} &= \\mathrm{tr} \\big[ \\big( (\\mathbf{A}^\\mathsf{dRPA} + \\mathbf{B}^\\mathsf{dRPA}) (\\mathbf{A}^\\mathsf{dRPA} - \\mathbf{B}^\\mathsf{dRPA}) \\big)^{1/2} \\big] \\\\\n",
    "&= \\mathrm{tr} \\big[ \\big( (\\mathbf{A}^\\mathsf{dRPA} - \\mathbf{B}^\\mathsf{dRPA})^{1/2} (\\mathbf{A}^\\mathsf{dRPA} + \\mathbf{B}^\\mathsf{dRPA}) (\\mathbf{A}^\\mathsf{dRPA} - \\mathbf{B}^\\mathsf{dRPA})^{1/2} \\big)^{1/2} \\big] \\\\\n",
    "&\\equiv \\mathrm{tr} (\\mathbf{M}^{1/2})\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "**(2)** $\\omega^\\mathsf{dTDA}_n$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "回顾式 (5) 所导出的 dTDA 激发能：\n",
    "\n",
    "$$\n",
    "\\mathbf{A}^\\mathsf{dTDA} \\mathbf{X}_n = \\omega^\\mathsf{dTDA}_n \\mathbf{X}_n\n",
    "$$\n",
    "\n",
    "我们能立即利用矩阵的迹等于其本征值的和，得到\n",
    "\n",
    "$$\n",
    "\\sum_n \\omega^\\mathsf{dTDA}_n = \\mathrm{tr} (\\mathbf{A}^\\mathsf{dTDA})\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "总结上述的结果，可以得到\n",
    "\n",
    "$$\n",
    "E^\\mathsf{dRPA}_\\mathrm{c} = \\frac{1}{2} \\sum_n (\\omega_n^\\mathsf{dRPA} - \\omega_n^\\mathsf{dTDA}) = \\frac{1}{2} \\big( \\mathrm{tr} (\\mathbf{M}^{1/2}) - \\mathrm{tr} (\\mathbf{A}^\\mathsf{dTDA}) \\big) = \\frac{1}{2} \\mathrm{tr} (\\mathbf{M}^{1/2} - \\mathbf{A}^\\mathsf{dTDA})\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 简单理解 dRPA 相关能 (1)：绝热路径与密度涨落"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里我们主要使用 Eshuis, Furche et al. [^Eshuis-Furche.TCA.2012.131] 的文章的思路来叙述；但这一段本身是 DFT 理论的基础，因此不仅是 dRPA，其它类型的相关能 (GGA, Hybrid, Double Hybrid) 都可以用下述框架作为基础推导。\n",
    "\n",
    "这里并非是对 DFT 理论的回顾，而是在对 DFT 理论有基础了解之后的一些补充理解。\n",
    "\n",
    "我们之后会提及，dRPA 具有两种解释方法。一种为类 TD-KS 方法，另一种为涨落耗散定理。从实现上，我们已经对类 TD-KS 方法做了说明。我们以后还会对涨落耗散定理的方法的实现作说明，并且会对这两种方法作推导。尽管这两种方法在公式表达上有巨大的差别，但结果相同；且其推导前提都是绝热路径与密度涨落。\n",
    "\n",
    "这一段完全是理论性的，不包含任何程序，也不包含任何近似 (除了 Kohn-Sham 图景本身或 Levy Constrained Search 之外)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 绝热路径 (1)：定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "关于绝热路径，较为基础但清晰的综述是 Perdew, Kurth [^Perdew-Kurth.Springer.2003] (p.16)。我们首先定义关于变量 $\\alpha$ 的电子态波函数哈密顿算符 (不包含核互斥部分) (后文中的 $\\alpha$ 一般都不指代向上自旋的含义)\n",
    "\n",
    "$$\n",
    "\\hat H^\\alpha = \\hat T + \\alpha \\hat V_\\mathrm{ee} + \\hat V_\\mathrm{ext} + \\hat V^\\alpha\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "其中，$\\hat T$ 为动能算符，$\\hat V_\\mathrm{ee}$ 为电子互斥算符 (下两式的 $i$ 暂时代表电子角标而非占据轨道)，$\\hat V_\\mathrm{ext}$ 在无外场的情况下定义为电子与原子互斥势算符 ($A$ 代表原子角标)：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\hat T &= - \\frac{1}{2} \\sum_{i} \\nabla_{\\boldsymbol{r}_i}^2 \\\\\n",
    "\\hat V_\\mathrm{ee} &= \\frac{1}{2} \\sum_{i \\neq j} \\frac{1}{| \\boldsymbol{r}_i - \\boldsymbol{r}_j |} \\\\\n",
    "\\hat V_\\mathrm{exc} &= \\sum_i v_\\mathrm{exc} (\\boldsymbol{r}_i) = - \\sum_{Ai} \\frac{Z_A}{| \\boldsymbol{r}_i - \\boldsymbol{r}_A |}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "而第三个算符 $\\hat V^\\alpha$ 定义如下。若 $\\alpha = 1$，则定义为零。这种情况下，$\\hat H^{\\alpha = 1}$ 恰好是精确的电子态哈密顿算符 $\\hat T + \\hat V_\\mathrm{ee} + \\hat V_\\mathrm{ext}$；而若 $\\alpha = 0$，在 DFT 下则是需要被定义的量，各种 DFT 的近似的目标也是希望描述清楚 $\\hat V_\\mathrm{xc}$；在我们的实际计算中，$\\alpha = 0$ 的情况对应 PBE 参考态的计算。\n",
    "\n",
    "即定义为交换相关势相关量。这对应的是 Kohn-Sham 电子态哈密顿算符，且不包含交换部分。我们之前计算所用到的 PBE，或者 BLYP, SVWN5 等即可以看作对该算符 $\\hat V^{\\alpha = 0}$ 的近似；但 B3LYP 则包含 0.2 份了交换，因此近似的对象不是 $\\hat V^{\\alpha = 0}$ (近似对象很接近 $\\hat V^{\\alpha = 0.2}$，但严格来说并非如此，因为 $0.2 \\hat V_\\mathrm{ee}$ 本质是双电子算符，因此其精确求解还是与 $\\alpha = 1$ 的情形没有本质区别，而不可能是杂化 DFT 近似的做法)，也因此不再这篇文档的讨论范畴中。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "若 Kohn-Sham 图景下可以构造出完全精确的交换相关势，那么 $\\hat H^{\\alpha = 0}$ 即使与 $\\hat V^{\\alpha = 1}$ 具有不同的形式，导出不同的波函数\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\hat H^{\\alpha = 1} | \\hat \\Psi^{\\alpha = 1} \\rangle &= E_\\mathrm{elec} | \\hat \\Psi^{\\alpha = 1} \\rangle \\\\\n",
    "\\hat H^{\\alpha = 0} | \\hat \\Psi^{\\alpha = 0} \\rangle &= E_\\mathrm{elec} | \\hat \\Psi^{\\alpha = 0} \\rangle\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "其中，$E_\\mathrm{elec}$ 是基态能量。\n",
    "\n",
    "之所以要这么绕弯子，是因为我们无法在较少计算量下得到真实的电子态波函数。从程序实现的角度讲，在 Kohn-Sham 图景下，假设真实的电子态密度 $\\rho = \\langle \\Psi^{\\alpha = 1} | \\hat \\rho | \\Psi^{\\alpha = 1} \\rangle$ 能够通过相互正交的、电子数量的关于电子坐标 $\\boldsymbol{r}$ 的函数 $\\phi_{i} (\\boldsymbol{r})$ 之和表示：$\\rho = \\langle \\Psi^{\\alpha = 0} | \\hat \\rho | \\Psi^{\\alpha = 0} \\rangle$。那么就存在势函数 $v^\\mathrm{xc} (\\boldsymbol{r}_i)$，使得 $\\hat H^{\\alpha = 0} | \\hat \\Psi^{\\alpha = 0} \\rangle$ 波函数的求解可以通过类似于 Hartree-Fock 的自洽场过程给出而不需要进行大计算量的 Post-HF 过程，但在这些有限的计算量下给出正确的密度。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "基于上述的定义，我们可以给出波函数 $| \\Psi^{\\alpha} \\rangle$ 关于 $\\alpha$ 变量的绝热路径。该“绝热路径”的守恒量是电子态密度，即对于任意 $\\alpha$，\n",
    "\n",
    "$$\n",
    "\\rho = \\langle \\Psi^\\alpha | \\hat \\rho | \\Psi^\\alpha \\rangle\n",
    "$$\n",
    "\n",
    "是完全相等的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 绝热路径 (2)：与相关能的联系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "DFT 近似的主要目标是给出交换相关能；上述的绝热路径是一种从波函数角度出发一窥交换相关能构造的做法。\n",
    "\n",
    "首先，总电子态能量 $E_\\mathrm{elec}$ (不包含核互斥能) 可以拆分为单电子轨道动能 $T_\\mathrm{s} [\\rho]$、外势能 $V_\\mathrm{ext} [\\rho]$、库伦积分 $J [\\rho]$：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "T_\\mathrm{s} [\\rho] &= \\langle \\Psi^{\\alpha = 0} | \\hat T | \\Psi^{\\alpha = 0} \\rangle \\\\\n",
    "V_\\mathrm{ext} [\\rho] &= \\int \\rho(\\boldsymbol{r}) v_\\mathrm{ext} (\\boldsymbol{r}) \\, \\mathrm{d} \\boldsymbol{r} \\\\\n",
    "U [\\rho] &= \\frac{1}{2} \\iint \\frac{\\rho(\\boldsymbol{r}) \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}'\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "上述三式是比较容易求取的。除此之外，定义交换能为\n",
    "\n",
    "$$\n",
    "E_\\mathrm{x} [\\rho] = \\langle \\Psi^{\\alpha = 0} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha = 0} \\rangle - U[\\rho]\n",
    "$$\n",
    "\n",
    "交换能可以通过类似与 Hartree-Fock 的方法给出。因此，上述四项都是程序容易实现，且应当仅与密度有关。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "下面我们就要给出相关能的表达式。它可以定义为\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c} [\\rho] &= E_\\mathrm{elec} [\\rho] - \\langle \\Psi^{\\alpha = 0} | \\hat H^{\\alpha = 1} | \\Psi^{\\alpha = 0} \\rangle \\\\\n",
    "&= \\langle \\Psi^{\\alpha = 0} | \\hat H^{\\alpha = 0} | \\Psi^{\\alpha = 0} \\rangle - \\langle \\Psi^{\\alpha = 0} | \\hat H^{\\alpha = 1} | \\Psi^{\\alpha = 0} \\rangle \\\\\n",
    "&= \\langle \\Psi^{\\alpha = 0} | \\hat V_\\mathrm{xc} | \\Psi^{\\alpha = 0} \\rangle - E_\\mathrm{x} [\\rho] \\tag{6}\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "也可以定义为\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c} [\\rho] &= \\langle \\Psi^{\\alpha = 1} | \\hat H^{\\alpha = 1} | \\Psi^{\\alpha = 1} \\rangle - \\langle \\Psi^{\\alpha = 0} | \\hat H^{\\alpha = 1} | \\Psi^{\\alpha = 0} \\rangle \\\\\n",
    "&= \\langle \\Psi^{\\alpha = 1} | \\hat T + \\hat V_\\mathrm{ee} | \\Psi^{\\alpha = 1} \\rangle - T_\\mathrm{s} [\\rho] - U[\\rho] - E_\\mathrm{x} [\\rho] \\\\\n",
    "&= \\langle \\Psi^{\\alpha = 1} | \\hat T + \\hat V_\\mathrm{ee} | \\Psi^{\\alpha = 1} \\rangle - \\langle \\Psi^{\\alpha = 0} | \\hat T | \\Psi^{\\alpha = 0} \\rangle - \\langle \\Psi^{\\alpha=0} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha=0} \\rangle \\tag{7}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "上式的前两项可以看作是关于 $\\alpha$ 定积分的上下界，因此上式也可以表达为\n",
    "\n",
    "$$\n",
    "E_\\mathrm{c} [\\rho] = \\int_0^1 \\frac{\\mathrm{d}}{\\mathrm{d} \\alpha} \\langle \\Psi^{\\alpha} | \\hat T + \\alpha \\hat V_\\mathrm{ee} | \\Psi^{\\alpha} \\rangle \\, \\mathrm{d} \\alpha - \\langle \\Psi^{\\alpha=0} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha=0} \\rangle\n",
    "$$\n",
    "\n",
    "根据 (变分情形而非本征情形的) Hellmann-Feynman 定理，有\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c} [\\rho]\n",
    "&= \\int_0^1 \\frac{\\mathrm{d}}{\\mathrm{d} \\alpha} \\langle \\Psi^{\\alpha} | \\alpha \\hat V_\\mathrm{ee} | \\Psi^{\\alpha} \\rangle \\, \\mathrm{d} \\alpha - \\langle \\Psi^{\\alpha=0} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha=0} \\rangle \\\\\n",
    "&= \\int_0^1 \\langle \\Psi^{\\alpha} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha} \\rangle \\, \\mathrm{d} \\alpha - U[\\rho] - E_\\mathrm{x} [\\rho] \\tag{8}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "式 (6) 是 Kohn-Sham 方式下最直观的交换能定义；它不包含真实波函数 $| \\Psi^{\\alpha = 1} \\rangle$ 的信息，但有目前只能依靠近似才能获得的 $\\hat V_\\mathrm{xc}$ 算符。式 (7) 或 (8) 则不包含 $\\hat V_\\mathrm{xc}$，但具有 $| \\Psi^{\\alpha = 1} \\rangle$。我们或许会认为后者的公式包含的已知或可知信息更多一些 (获取 $| \\Psi^{\\alpha = 1} \\rangle$ 计算量巨大的，避免获取之也是 DFT 近似的发展动力，但它在小体系有限基组下仍然是可求得的，并且更容易进行后自洽行为的分析)，因此我们将着重对式 (8) 进行考察。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 二次量子化 (1)：$\\hat V_\\mathrm{ee}$ 与 $\\hat \\rho (\\boldsymbol{r})$ 的定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "这里我们参考 Helgaker et al. [^Helgaker-Jorgensen.Wiley.2013] 的说明。由于我们推导的是闭壳层的情形，因此我们需要引入单重激发算符 (仅在下式中的 $\\alpha$ 代表自旋的含义)\n",
    "\n",
    "$$\n",
    "\\hat E_{pq} = a_{p \\alpha}^\\dagger a_{q \\alpha} + a_{p \\beta}^\\dagger a_{q \\beta}\n",
    "$$\n",
    "\n",
    "这里规定，当 $a$ 字母不在角标处时，则表示产生或湮灭算符。由此出发，我们能定义双电子算符 (Helgaker, eq 2.2.15)：\n",
    "\n",
    "$$\n",
    "\\hat V_\\mathrm{ee} = \\frac{1}{2} \\sum_{\\sigma, \\sigma'} \\sum_{pq, rs} (pq|rs) a_{p \\sigma}^\\dagger a_{r \\sigma}^\\dagger a_{s \\sigma'} a_{q \\sigma'} = \\frac{1}{2} \\sum_{pq, rs} (pq|rs) (\\hat E_{pq} \\hat E_{rs} - \\delta_{pr} \\hat E_{qs})\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "随后，我们定义密度算符 $\\hat \\rho(\\boldsymbol{r})$ (Eshuis, Furche [^Eshuis-Furche.TCA.2012.131], eq 11) (需要留意，Helgaker 的算符定义应都出于程序实现的要求，不会出现关于坐标呈变值的算符)：\n",
    "\n",
    "$$\n",
    "\\hat \\rho (\\boldsymbol{r}) = \\sum_{pq} \\hat E_{pq} \\phi_p (\\boldsymbol{r}) \\phi_q (\\boldsymbol{r})\n",
    "$$\n",
    "\n",
    "其中，$\\phi_p (\\boldsymbol{r})$ 表示轨道 $p$ 的分子轨道函数。这里的分子轨道指代的是作为 $\\alpha = 0$ 参考态的轨道。容易知道密度算符具有下述性质：\n",
    "\n",
    "$$\n",
    "\\rho (\\boldsymbol{r}) = \\langle \\Psi^{\\alpha} | \\hat \\rho(\\boldsymbol{r}) | \\Psi^{\\alpha} \\rangle\n",
    "$$\n",
    "\n",
    "但需要注意到，下述不等号一般情况下是成立的：\n",
    "\n",
    "$$\n",
    "\\rho (\\boldsymbol{r}) \\rho (\\boldsymbol{r}') \\neq \\langle \\Psi^{\\alpha} | \\hat \\rho(\\boldsymbol{r}) \\hat \\rho(\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们或许还需要定义双坐标密度算符 $\\hat \\rho (\\boldsymbol{r}, \\boldsymbol{r}')$：\n",
    "\n",
    "$$\n",
    "\\hat \\rho (\\boldsymbol{r}, \\boldsymbol{r}') = \\sum_{pq} \\hat E_{pq} \\phi_p (\\boldsymbol{r}) \\phi_q (\\boldsymbol{r}')\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "以及 delta 算符 $\\hat \\delta (\\boldsymbol{r}, \\boldsymbol{r}')$，注意到下述定义与 Dirac Delta 函数应当是等价的：\n",
    "\n",
    "$$\n",
    "\\hat \\delta (\\boldsymbol{r}, \\boldsymbol{r}') = \\sum_{pq} \\delta_{pq} \\phi_p (\\boldsymbol{r}) \\phi_q (\\boldsymbol{r}') = \\delta (\\boldsymbol{r} - \\boldsymbol{r}')\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此，我们可以重述算符 $\\hat V_\\mathrm{ee}$ 为\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\hat V_\\mathrm{ee} &= \\frac{1}{2} \\iint \\frac{\\hat \\rho(\\boldsymbol{r}) \\hat \\rho(\\boldsymbol{r}') - \\hat \\delta (\\boldsymbol{r}, \\boldsymbol{r}') \\hat \\rho(\\boldsymbol{r}, \\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' \\\\\n",
    "&= \\frac{1}{2} \\iint \\frac{\\hat \\rho(\\boldsymbol{r}) \\hat \\rho(\\boldsymbol{r}') - \\delta(\\boldsymbol{r} - \\boldsymbol{r}') \\hat \\rho(\\boldsymbol{r})}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}'\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "上述等式中或许存在一项非常特殊的表达式：\n",
    "\n",
    "$$\n",
    "\\hat V_\\mathrm{ee} \\leftarrow\n",
    "- \\frac{1}{2} \\iint \\frac{\\delta(\\boldsymbol{r} - \\boldsymbol{r}') \\hat \\rho(\\boldsymbol{r})}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' = - \\frac{1}{2} \\int \\frac{\\hat \\rho(\\boldsymbol{r})}{0} \\, \\mathrm{d} \\boldsymbol{r} = \\mathrm{NaN}\n",
    "$$\n",
    "\n",
    "这项中，无论左乘右乘何种波函数，$\\hat \\rho (\\boldsymbol{r})$ 具体表达式如何，其结果一定为非数 (NaN, Not a Number)。如果将 $\\delta$ 函数当作一种逼近极限的话，应当认为上述值比起 NaN 来说更接近 $- \\infty$。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "显然，我们知道 $\\langle \\Psi^{\\alpha} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha} \\rangle$ 是有界的，且在 $\\alpha = 0$ 时代表库伦积分与交换能之和。但上述分项为 NaN，那么一定也就意味着\n",
    "\n",
    "$$\n",
    "\\hat V_\\mathrm{ee} \\leftarrow\n",
    "- \\frac{1}{2} \\iint \\frac{\\hat \\rho(\\boldsymbol{r}) \\hat \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' = \\mathrm{NaN}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 二次量子化 (2)：密度涨落算符 $\\Delta \\hat \\rho (\\boldsymbol{r})$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "随后我们引入密度涨落算符\n",
    "\n",
    "$$\n",
    "\\Delta \\hat \\rho(\\boldsymbol{r}) = \\hat \\rho(\\boldsymbol{r}) - \\rho(\\boldsymbol{r})\n",
    "$$\n",
    "\n",
    "密度涨落算符并不是一定要引入的算符；这我们会在后面一段推导时会提及。类似地，我们也能了解到性质\n",
    "\n",
    "$$\n",
    "0 = \\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho(\\boldsymbol{r}) | \\Psi^{\\alpha} \\rangle\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "将密度涨落算符的定义代入，我们还可以重述算符 $\\hat V_\\mathrm{ee}$ 为\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\hat V_\\mathrm{ee} &=\n",
    "\\frac{1}{2} \\iint \\frac{\\Delta \\hat \\rho(\\boldsymbol{r}) \\Delta \\hat \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' \\\\\n",
    "&\\quad + \\frac{1}{2} \\iint \\frac{\\Delta \\hat \\rho(\\boldsymbol{r}) \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}'\n",
    "+ \\frac{1}{2} \\iint \\frac{\\rho(\\boldsymbol{r}) \\Delta \\hat \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' \\\\\n",
    "&\\quad - \\frac{1}{2} \\iint \\frac{\\delta(\\boldsymbol{r} - \\boldsymbol{r}') \\hat \\rho(\\boldsymbol{r})}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}'\n",
    "+ U[\\rho]\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们在这里指出，由于后四个贡献项都仅与单个密度算符、或密度涨落算符有关，因此在左乘 $\\langle \\Psi^{\\alpha} |$ 右乘 $| \\Psi^{\\alpha} \\rangle$ 后，不论 $\\alpha$ 的值是多少，其结果都应当相等 (因为对任意 $\\alpha$ 的 $| \\Psi^{\\alpha} \\rangle$，其密度相等)。举其中一个例子而言，\n",
    "\n",
    "$$\n",
    "\\frac{1}{2} \\langle \\Psi^\\alpha | \\iint \\frac{\\Delta \\hat \\rho(\\boldsymbol{r}) \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' | \\Psi^\\alpha \\rangle\n",
    "= \\iint \\frac{\\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\langle \\Psi^\\alpha | \\Delta \\hat \\rho(\\boldsymbol{r}) | \\Psi^\\alpha \\rangle  \\, \\mathrm{d} \\boldsymbol{r}\\, \\mathrm{d} \\boldsymbol{r}'\n",
    "= 0\n",
    "$$\n",
    "\n",
    "之所以上式中对 $\\boldsymbol{r}, \\boldsymbol{r}'$ 的积分，与左右矢符号可以交换，是借了二次量子化算符 $a_p^\\dagger, a_p$ 等算符与电子坐标 $\\boldsymbol{r}$ 无关的便利。因此，能真正区别不同波函数的算符贡献项，只有上式中的第一项。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "根据上述说明，我们可以对绝热路径与相关能的关联式 (8) 重新写为\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c} [\\rho]\n",
    "&= \\int_0^1 \\langle \\Psi^{\\alpha} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha} \\rangle \\, \\mathrm{d} \\alpha - \\langle \\Psi^{\\alpha=0} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha=0} \\rangle \\\\\n",
    "&= \\int_0^1 \\big( \\langle \\Psi^{\\alpha} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha} \\rangle - \\langle \\Psi^{\\alpha=0} | \\hat V_\\mathrm{ee} | \\Psi^{\\alpha=0} \\rangle \\big) \\, \\mathrm{d} \\alpha \\\\\n",
    "&= \\frac{1}{2} \\int_0^1 \\, \\mathrm{d} \\alpha \\iint \\, \\mathrm{d} \\boldsymbol{r}\\, \\mathrm{d} \\boldsymbol{r}' \\frac{\\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle - \\langle \\Psi^{\\alpha=0} | \\Delta \\hat \\rho (\\boldsymbol{r}) \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha=0} \\rangle}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\tag{9}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 幺元分解：建立相关能与激发态的联系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "在波函数空间下，我们将所有满足定态方程\n",
    "\n",
    "$$\n",
    "\\hat H^\\alpha | \\Psi_n^\\alpha \\rangle = (E_\\mathrm{elec} + \\omega_n^\\alpha) | \\Psi_n^\\alpha \\rangle\n",
    "$$\n",
    "\n",
    "的波函数 $| \\Psi_n^\\alpha \\rangle$ 归并在一起 $\\{ | \\Psi_n^\\alpha \\rangle \\}$；该解空间与 $\\{ | \\Psi^\\alpha \\rangle \\}$ 的并集假定认为是完备的。其中，$\\omega_n^\\alpha$ 称作在绝热路径 $\\alpha$ 基态波函数上的第 $n$ 个激发态的激发能量。我们不把基态列入 $n$ 的角标范围中，或者说 $n$ 不能取到 0；这种记号可能有别于一些文章。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "定义了上述记号并作完备性的假定后，尽管不很严谨，但我们指出存在下述幺元分解 (RI, Resolution of Identity)：\n",
    "\n",
    "$$\n",
    "| \\Psi^\\alpha \\rangle \\langle \\Psi^\\alpha | + \\sum_{n} | \\Psi_n^\\alpha \\rangle \\langle \\Psi_n^\\alpha | = 1\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此，我们可以将式 (9) 中的一部分分项写作\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle\n",
    "&= \\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) | \\Psi^\\alpha \\rangle \\langle \\Psi^\\alpha | \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle + \\sum_n \\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) | \\Psi_n^\\alpha \\rangle \\langle \\Psi_n^\\alpha | \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle \\\\\n",
    "&= \\sum_{n} \\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) | \\Psi_n^\\alpha \\rangle \\langle \\Psi_n^\\alpha | \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "上式的第二个等号利用的是基态波函数的 $\\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) | \\Psi^\\alpha \\rangle = 0$。这样，我们就将相关能与激发态之间建立了联系。我们也会记跃迁密度为\n",
    "\n",
    "$$\n",
    "\\rho_{0n}^\\mathrm{\\alpha} (\\boldsymbol{r}) = \\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) | \\Psi_n^\\alpha \\rangle = \\langle \\Psi^{\\alpha} | \\hat \\rho (\\boldsymbol{r}) | \\Psi_n^\\alpha \\rangle \n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "之所以说“完备性”是假定，是因为并不是所有激发态都被囊括了进来；譬如三重态激发在推导与程序中就不在其中。当然，我们考虑一般的跃迁密度时，单重到三重的激发是禁阻的，因此三重激发也不需要出现在幺元分解式中。因此，这种“完备性”尽管一点都不完备，但基本是够用的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "事实上，从上式中能看出，由于在描述基态到激发态的跃迁过程时，$\\Delta \\hat \\rho (\\boldsymbol{r})$ 与 $\\hat \\rho (\\boldsymbol{r})$ 没有本质区别，因此会说额外定义密度涨落算符不一定非常实际的意义；当然，用涨落算符会在公式中更加凸显相关能与密度波动之间的联系。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "最后，我们需要指出，单看下式的话，\n",
    "\n",
    "$$\n",
    "\\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle = \\mathrm{NaN}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "如果从跃迁密度的角度讲，上式相当于对所有激发态的跃迁密度平方的求和：\n",
    "\n",
    "$$\n",
    "\\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle = \\sum_{n} \\rho_{0n}^{\\alpha} (\\boldsymbol{r}) \\rho_{0n}^{\\alpha, \\dagger} (\\boldsymbol{r}')\n",
    "$$\n",
    "\n",
    "上式的 $\\dagger$ 表示的是复共轭。显然，每个激发态相对于基态密度的扰动都是比较大的，因此每个跃迁密度本身不可能是无穷小量；加之激发态数量无限，因此上述求和也是无限的，不可能是有界量。(当然，对于有限基组而言这显然是有界量)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "而如果从 $\\hat V_\\mathrm{ee}$ 的拆分角度来讲也是同样的。我们之前指出过，\n",
    "\n",
    "$$\n",
    "\\hat V_\\mathrm{ee} \\leftarrow\n",
    "- \\frac{1}{2} \\iint \\frac{\\hat \\rho(\\boldsymbol{r}) \\hat \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' = \\mathrm{NaN}\n",
    "$$\n",
    "\n",
    "只需要一些简单的分析，应当不难知道\n",
    "\n",
    "$$\n",
    "\\frac{1}{2} \\langle \\Psi^\\alpha | \\iint \\frac{\\hat \\rho(\\boldsymbol{r}) \\hat \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' | \\Psi^\\alpha \\rangle\n",
    "= \\frac{1}{2} \\langle \\Psi^\\alpha | \\iint \\frac{\\Delta \\hat \\rho(\\boldsymbol{r}) \\Delta \\hat \\rho(\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}' | \\Psi^\\alpha \\rangle + U[\\rho]\n",
    "$$\n",
    "\n",
    "因此我们应当预期 $\\Delta \\hat \\rho(\\boldsymbol{r}) \\Delta \\hat \\rho(\\boldsymbol{r}')$ 与 $\\hat \\rho(\\boldsymbol{r}) \\hat \\rho(\\boldsymbol{r}')$ 具有比较接近的性质。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此，单就讨论 $\\langle \\Psi^{\\alpha} | \\Delta \\hat \\rho (\\boldsymbol{r}) \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha} \\rangle$ 本身是不能得到结论的，而需要与 $\\langle \\Psi^{\\alpha = 0} | \\Delta \\hat \\rho (\\boldsymbol{r}) \\Delta \\hat \\rho (\\boldsymbol{r}') | \\Psi^{\\alpha = 0} \\rangle$ 相减才能得到有界的相关能。最后指出，我们可以将相关能式 (9) 写作\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c} [\\rho]\n",
    "&= \\frac{1}{2} \\int_0^1 \\, \\mathrm{d} \\alpha \\iint \\, \\mathrm{d} \\boldsymbol{r}\\, \\mathrm{d} \\boldsymbol{r}' \\left( \\sum_{n} \\frac{\\rho_{0n}^{\\alpha} (\\boldsymbol{r}) \\rho_{0n}^{\\alpha, \\dagger} (\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} - \\sum_{n} \\frac{\\rho_{0n}^{\\alpha=0} (\\boldsymbol{r}) \\rho_{0n}^{\\alpha=0, \\dagger} (\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\right) \\tag{10}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "从程序实现来说，跃迁密度不会是非实数量，因此共轭记号 $\\dagger$ 一般是可以去掉的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 简单理解 dRPA 相关能 (2)：类 TD-KS 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "dRPA 相关能的推导一般可以有三种方式，为类 TD-KS (Time-Dependent Kohn-Sham) 方法、涨落耗散理论 (Fluctuation Dissipation Theory)、以及格林函数 (GW, Green's Wavefunction) 途径。在这篇文档中，我们只讨论前两种方法；他们的共同基础是上面的绝热路径与密度涨落。通过密度涨落，我们建立了相关能与激发态的联系。\n",
    "\n",
    "激发态很容易地与 TD-KS 方法产生直观的联系。我们下面就会讨论如何从 TD-KS 近似得到 dRPA 相关能。我们仍然按照 Eshuis, Furche [^Eshuis-Furche.TCA.2012.131] 的思路来理解。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### TD Hartree 近似与跃迁密度的联系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "在这里我们不陈述 TD-KS 方程是如何推导的，只说明结论。\n",
    "\n",
    "首先，如前所述，dRPA 相关能的交换部分是通过精确交换能表达式给出的；因此之后我们的讨论中就不引入交换能。我们考察的波函数 $| \\Psi^{\\alpha = 0} \\rangle$ 作为仅包含单电子算符贡献的 Kohn-Sham 等效哈密顿算符 $\\hat H^{\\alpha = 0}$ 的本征态，其形式并不取用 Slater 行列式，而令其为 Hartree 连乘积。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "对于波函数 $| \\Psi^{\\alpha = 0} \\rangle$，其 TD-KS 方程 (Casida 方程) 列为\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\begin{pmatrix} \\mathbf{A}^\\alpha & \\mathbf{B}^\\alpha \\\\ - \\mathbf{B}^\\alpha & - \\mathbf{A}^\\alpha \\end{pmatrix}\n",
    "\\begin{pmatrix} \\mathbf{X}_n^\\alpha \\\\ \\mathbf{Y}_n^\\alpha \\end{pmatrix}\n",
    "= \\pm \\omega_n^\\alpha \\begin{pmatrix} \\mathbf{X}_n^\\alpha \\\\ \\mathbf{Y}_n^\\alpha \\end{pmatrix} \\tag{11}\n",
    "\\end{equation}\n",
    "$$\n",
    "\n",
    "其中，\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "A_{ia, jb}^\\alpha &= - (\\varepsilon_i - \\varepsilon_a) \\delta_{ij} \\delta_{ab} + 2 \\alpha (ia|jb) + f^{\\mathrm{xc}, \\alpha}_{ia, jb} \\\\\n",
    "B_{ia, jb}^\\alpha &= 2 \\alpha (ia|jb) + f^{\\mathrm{xc}, \\alpha}_{ia, jb} \\tag{12}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "如果我们将交换相关能对 TD-KS 方程的贡献全部抹去，那么上式就化为 TD Hartree 的情况：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "A_{ia, jb}^\\alpha &\\simeq - (\\varepsilon_i - \\varepsilon_a) \\delta_{ij} \\delta_{ab} + 2 \\alpha (ia|jb) \\\\\n",
    "B_{ia, jb}^\\alpha &\\simeq 2 \\alpha (ia|jb) \\tag{13}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "尽管这一段大体是公式推导，但我们顺便在此定义一些程序计算用的函数。定义函数 `A` $A_{ia, jb}^\\alpha$, `B` $B_{ia, jb}^\\alpha$，它们通过输入参数 $\\alpha$ 给出张量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "def A(alpha):\n",
    "    return (np.einsum(\"ia, ij, ab -> iajb\", - eo[:, None] + ev[None, :], delta_ij, delta_ab) + 2 * alpha * eri0_iajb).reshape(nocc*nvir, nocc*nvir)\n",
    "\n",
    "def B(alpha):\n",
    "    return (2 * alpha * eri0_iajb).reshape(nocc*nvir, nocc*nvir)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "同时，我们定义函数 `omega_list`，通过分别输入 A 与 B 张量对应的 $\\alpha$ 值，给出其 TD 方程的正频率列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "def omega_list(alpha1, alpha2=None):\n",
    "    alpha2 = alpha2 if alpha2 is not None else alpha1\n",
    "    A_, B_ = A(alpha1), B(alpha2)\n",
    "    eig = np.linalg.eig((A_ + B_) @ (A_ - B_))[0]\n",
    "    eig.sort()\n",
    "    return np.sqrt(eig)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "上述函数能直接计算 dRPA 相关能：\n",
    "\n",
    "$$\n",
    "E^\\mathsf{dRPA}_\\mathrm{c} = \\frac{1}{2} \\sum_n (\\omega_n^\\mathsf{dRPA} - \\omega_n^\\mathsf{dTDA})\n",
    "$$\n",
    "\n",
    "我们留意到 dRPA 激发使用的是 $A_{ia, jb}^{\\alpha = 1}$, $B_{ia, jb}^{\\alpha = 1}$，而 dTDA 激发使用的是 $A_{ia, jb}^{\\alpha = 1}$, $B_{ia, jb}^{\\alpha = 0}$："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.4313792211675036"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "0.5 * (omega_list(1).sum() - omega_list(1, 0).sum())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们在这篇文档中不对作为本征向量的 $X_{n, ia}^\\alpha$ 与 $Y_{n, ia}^\\alpha$ 作程序上的定义，仅作讨论。该本征向量在 PySCF 的程序中作下述归一化定义：\n",
    "\n",
    "$$\n",
    "\\sum_{ia} \\big( (X_{n, ia}^\\alpha)^2 - (Y_{n, ia}^\\alpha)^2 \\big) = \\frac{1}{2}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "基于上述定义，闭壳层下的 TD 跃迁密度可以定义为 (这也参考 PySCF 的跃迁偶极矩定义)：\n",
    "\n",
    "$$\n",
    "\\rho_{0n}^\\alpha (\\boldsymbol{r}) = 2 \\sum_{ia} (X_{n, ia}^\\alpha + Y_{n, ia}^\\alpha) \\phi_i (\\boldsymbol{r}) \\phi_a (\\boldsymbol{r})\n",
    "$$\n",
    "\n",
    "其中的 2 倍源于闭壳层下的两种自旋贡献之和。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### TD 左右矢定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "在后文中，为了公式推导与表达的便利，这里借用 Eshuis, Furche [^Eshuis-Furche.TCA.2012.131] 中的符号；但需要留意，实际闭壳层程序与原文开壳层的推导在一些细节上有出入。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们可以定义下述与 TD 方程等价的表达式：\n",
    "\n",
    "$$\n",
    "( \\mathbf{\\Lambda}^\\alpha - \\omega_n^\\alpha \\mathbf{\\Delta} ) | \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle = 0\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "其中，上式定义\n",
    "\n",
    "$$\n",
    "\\mathbf{\\Lambda}^\\alpha = \\begin{pmatrix} \\mathbf{A}^\\alpha & \\mathbf{B}^\\alpha \\\\ \\mathbf{B}^\\alpha & \\mathbf{A}^\\alpha \\end{pmatrix} , \\quad\n",
    "\\mathbf{\\Delta} = \\begin{pmatrix} \\mathbf{1} & \\mathbf{0} \\\\ \\mathbf{0} & -\\mathbf{1} \\end{pmatrix}\n",
    "$$\n",
    "\n",
    "以及右矢 $| \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle$ 可以看作列向量；相对应地，左矢 $\\langle \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha |$ 可以看作行向量。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "经过上述定义，特征向量的归一化条件可以写为\n",
    "\n",
    "$$\n",
    "\\langle \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha | \\mathbf{\\Delta} | \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle = \\frac{1}{2}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此，我们可以从相关能表达式 (10) 出发，写出其中的第一项贡献：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c} [\\rho]\n",
    "&\\leftarrow \\frac{1}{2} \\int_0^1 \\, \\mathrm{d} \\alpha \\iint \\, \\mathrm{d} \\boldsymbol{r}\\, \\mathrm{d} \\boldsymbol{r}' \\sum_{n} \\frac{\\rho_{0n}^{\\alpha} (\\boldsymbol{r}) \\rho_{0n}^{\\alpha, \\dagger} (\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\\\\n",
    "&= \\frac{1}{2} \\cdot 4 \\int_0^1 \\, \\mathrm{d} \\alpha \\iint \\, \\mathrm{d} \\boldsymbol{r}\\, \\mathrm{d} \\boldsymbol{r}' \\sum_{n} (X_{n, ia}^\\alpha + Y_{n, ia}^\\alpha) \\cdot \\sum_{ia, jb} \\frac{\\phi_i (\\boldsymbol{r}) \\phi_a (\\boldsymbol{r}) \\phi_j (\\boldsymbol{r}') \\phi_b (\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\cdot (X_{n, jb}^\\alpha + Y_{n, jb}^\\alpha) \\\\\n",
    "&= \\frac{1}{2} \\cdot 4 \\int_0^1 \\sum_{n} \\langle \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha | \\mathbf{g} \\mathbf{I} | \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle \\, \\mathrm{d} \\alpha \n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "其中，我们定义了双电子张量以及分块单位矩阵\n",
    "\n",
    "$$\n",
    "g_{ia, jb} = (ia|jb), \\quad \\mathbf{I} = \\begin{pmatrix} \\mathbf{1} & \\mathbf{1} \\\\ \\mathbf{1} & \\mathbf{1} \\end{pmatrix}\n",
    "$$\n",
    "\n",
    "那么我们会写\n",
    "\n",
    "$$\n",
    "\\mathbf{g} \\mathbf{I} = \\begin{pmatrix} \\mathbf{g} & \\mathbf{g} \\\\ \\mathbf{g} & \\mathbf{g} \\end{pmatrix}\n",
    "$$\n",
    "\n",
    "以及上式的 4 倍是从两个闭壳层跃迁密度的 2 倍系数相乘获得的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "对于式 (10) 的第二项同理。因此，我们可以写\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "E_\\mathrm{c} [\\rho]\n",
    "= \\frac{1}{2} \\cdot 4 \\int_0^1 \\sum_{n} \\langle \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha | \\mathbf{gI} | \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle \\, \\mathrm{d} \\alpha\n",
    "- \\frac{1}{2} \\cdot 4 \\sum_{n} \\langle \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} | \\mathbf{gI} | \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} \\rangle \\tag{14}\n",
    "\\end{equation}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### TD 方程的 Hellmann-Feynman 定理应用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "对于上式 (14)，其第一项中的关于绝热路径参数 $\\alpha$ 的积分相对来说比较难处理。但很有意思的是，对 TD 方程应用 Hellmann-Feynman 定理求取关于 $\\alpha$ 的母函数，可以解决这个问题。\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "0 &= \\frac{\\mathrm{d}}{\\mathrm{d} \\alpha} \\langle \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha | ( \\mathbf{\\Lambda}^\\alpha - \\omega_n^\\alpha \\mathbf{\\Delta} ) | \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle \\\\\n",
    "&= \\langle \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha | \\frac{\\mathrm{d}}{\\mathrm{d} \\alpha} ( \\mathbf{\\Lambda}^\\alpha - \\omega_n^\\alpha \\mathbf{\\Delta} ) | \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle \\\\\n",
    "&= \\langle \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha | \\frac{\\mathrm{d}}{\\mathrm{d} \\alpha} \\mathbf{\\Lambda}^\\alpha | \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle - \\frac{1}{2} \\frac{\\mathrm{d} \\omega_n^\\alpha}{\\mathrm{d} \\alpha}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们之前提到过，在 dRPA 相关能计算中会将 $f^{\\mathrm{xc}, \\alpha}_{ia, jb}$ 完全近似为零，因此\n",
    "\n",
    "$$\n",
    "\\frac{\\mathrm{d}}{\\mathrm{d} \\alpha} \\mathbf{\\Lambda}^\\alpha = \\frac{\\mathrm{d}}{\\mathrm{d} \\alpha} \\begin{pmatrix} \\mathbf{A}^\\alpha & \\mathbf{B}^\\alpha \\\\ \\mathbf{B}^\\alpha & \\mathbf{A}^\\alpha \\end{pmatrix} \\simeq 2 \\mathbf{g} \\begin{pmatrix} \\mathbf{1} & \\mathbf{1} \\\\ \\mathbf{1} & \\mathbf{1} \\end{pmatrix} = 2 \\mathbf{gI}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此，\n",
    "\n",
    "$$\n",
    "\\frac{\\mathrm{d} \\omega_n^\\alpha}{\\mathrm{d} \\alpha} \\simeq 4 \\langle \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha | \\mathbf{gI} | \\mathbf{X}_n^\\alpha, \\mathbf{Y}_n^\\alpha \\rangle\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "基于上述推导，我们可以将式 (14) 的相关能再写作\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c} [\\rho]\n",
    "&\\simeq \\frac{1}{2} \\int_0^1 \\sum_{n} \\frac{\\mathrm{d} \\omega_n^\\alpha}{\\mathrm{d} \\alpha} \\, \\mathrm{d} \\alpha - \\frac{1}{2} \\cdot 4 \\sum_{n} \\langle \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} | \\mathbf{gI} | \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} \\rangle \\\\\n",
    "&= \\frac{1}{2} \\left( \\sum_{n} \\omega_n^{\\alpha = 1} - \\sum_{n} \\omega_n^{\\alpha = 0} \\right) - \\frac{1}{2} \\cdot 4 \\sum_{n} \\langle \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} | \\mathbf{gI} | \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} \\rangle \\tag{15}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "上式的 $\\alpha = 1$ 的情形对应的即是 PySCF 的 dRPA 方法，这在前文中已经作了足够多描述了。而事实上，上式中所有 $\\alpha = 0$ 部分的贡献之和的相反数恰好是 PySCF 的 dTDA 方法对应的激发频率之和。我们马上说明这个问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 绝热路径 $\\alpha = 0$ 贡献与 dTDA 激发频率的关系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "式 (15) 所表达的相关能从表达上，显然可以简化为\n",
    "\n",
    "$$\n",
    "E_\\mathrm{c} [\\rho] \\simeq \\frac{1}{2} \\left( \\sum_{n} \\omega_n^{\\alpha = 1} - \\sum_{n} \\omega_n^{\\alpha = 0} \\right) - \\frac{1}{2} \\sum_{n} \\frac{\\mathrm{d} \\omega_n^{\\alpha = 0}}{\\mathrm{d} \\alpha}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "但我们刻意没有使用该式。我们知道，对于 $\\omega_n^{\\alpha = 1}, \\omega_n^{\\alpha = 0}$，是可以用类 TD-KS 方程求解的，并且我们将 $f_{ia, jb}^{\\mathrm{xc}, \\alpha}$ 近似为零，因此相当于是已知量了。但 $\\mathrm{d} \\omega_n^{\\alpha = 0} / \\mathrm{d} \\alpha$ 表现的是一种随着 $\\alpha$ 值变化的趋势；我们对 $\\alpha$ 固定的情况可以有充分的了解，但其变化我们很难把握。事实上，之前的公式都是在尽力避免出现可变的 $\\alpha$ 值，而尽量将 $\\alpha$ 变为 0 或 1。因此，我们之后的尝试不应是对表现 $\\alpha$ 趋势的 $\\mathrm{d} \\omega_n^{\\alpha = 0} / \\mathrm{d} \\alpha$ 作讨论，而是对固定了 $\\alpha = 0$ 的 $\\langle \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} | \\mathbf{g} | \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} \\rangle$ 作讨论。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们首先考察 $\\alpha = 0$ 的 A、B 张量：\n",
    "\n",
    "$$\n",
    "A_{ia, jb}^{\\alpha = 0} = - (\\varepsilon_i - \\varepsilon_a) \\delta_{ij} \\delta_{ab}, \\quad B_{ia, jb}^\\alpha = 0\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "对于有限基组，$n$ 作为激发态的角标，其维度是 $n_\\mathrm{occ} n_\\mathrm{vir}$；并且事实上，该角标在 $\\alpha = 0$ 是确实地可以与 $ia$ 角标作对应；我们应当很容易地定义并推知，\n",
    "\n",
    "$$\n",
    "\\omega_{ia}^{\\alpha = 0} = - (\\varepsilon_i - \\varepsilon_a)\n",
    "$$\n",
    "\n",
    "就等价于轨道能的差减。其本征函数也是非常容易推知的：\n",
    "\n",
    "$$\n",
    "X_{jb, ia}^{\\alpha = 0} = \\frac{1}{\\sqrt{2}} \\delta_{ij} \\delta_{ab}, \\quad Y_{jb, ia}^{\\alpha = 0} = 0\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "上式的 $1/\\sqrt{2}$ 的意义在于满足归一化条件 $\\langle \\mathbf{X}_n^{\\alpha = 0}, \\mathbf{Y}_n^{\\alpha = 0} | \\mathbf{\\Delta} | \\mathbf{X}_n^{\\alpha = 0}, \\mathbf{Y}_n^{\\alpha = 0} \\rangle = 1 / 2$。因此，\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "&\\quad 4 \\sum_{n} \\langle \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} | \\mathbf{gI} | \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} \\rangle \\\\\n",
    "&= 4 \\sum_{ia, jb, n=kc} (X_{kc, ia}^{\\alpha = 0} + Y_{kc, ia}^{\\alpha = 0}) (ia|jb) (X_{kc, jb}^{\\alpha = 0} + Y_{kc, jb}^{\\alpha = 0}) \\\\\n",
    "&= 2 \\sum_{ia, jb, kc} \\delta_{ki} \\delta_{ca} (ia|jb) \\delta_{kj} \\delta_{cb} = 2 \\sum_{kc} (kc|kc) \\\\\n",
    "&= 2 \\sum_{ia} (ia|ia)\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此，\n",
    "\n",
    "$$\n",
    "\\sum_{n \\neq 0} \\big( \\omega_n^{\\alpha = 0} + 4 \\langle \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} | \\mathbf{gI} | \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} \\rangle \\big) = \\sum_{ia} \\big( - (\\varepsilon_i - \\varepsilon_a) + 2 (ia|ia) \\big)\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们再回顾一下 dTDA 激发能的公式：\n",
    "\n",
    "$$\n",
    "\\sum_n \\omega^\\mathsf{dTDA}_n = \\mathrm{tr} (\\mathbf{A}^\\mathsf{dTDA})\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "而 $A_{ia, jb}^\\mathsf{dTDA} = - (\\varepsilon_i - \\varepsilon_a) \\delta_{ij} \\delta_{ab} + 2 (ia|jb)$，因此其迹恰好就有\n",
    "\n",
    "$$\n",
    "\\sum_{n \\neq 0} \\big( \\omega_n^{\\alpha = 0} + 4 \\langle \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} | \\mathbf{gI} | \\mathbf{X}_n^{\\alpha=0}, \\mathbf{Y}_n^{\\alpha=0} \\rangle \\big) = \\mathrm{tr} (\\mathbf{A}^\\mathsf{dTDA}) = \\sum_n \\omega^\\mathsf{dTDA}_n\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "而我们又陈述过 $\\omega_n^\\alpha = \\omega_n^\\mathsf{dRPA}$，因此式 (15) 所表达的相关能则可以写为\n",
    "\n",
    "$$\n",
    "E_\\mathrm{c} [\\rho] = \\frac{1}{2} \\sum_{n} ( \\omega_n^\\mathsf{dRPA} - \\omega_n^\\mathsf{dTDA} )\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "事实上，上述推导过程并没有真正地用到 dTDA 激发近似的原理和思路，只是结论上恰好一致而已。真正用到的近似是 dRPA 激发近似，即将 $f_{ia, jb}^{\\mathrm{xc}, \\alpha}$ 近似为零。\n",
    "\n",
    "至此，从类 TD-KS 方程角度出发解释的相关能推导，就已经全部完成了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 程序实现：$O(N^4)$ 的 RI 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "关于该方法的程序实现，主要是参考 Ren, Scheffler et al. [^Ren-Scheffler.NJP.2012.14] 的文献。但该文献中的一些公式的表达不太友好，也有部分公式错误，阅读时可能需要留些心眼。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 拓展的 Gauss-Legendre 格点"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "关于该 RI 的实现，我们需要先对格点积分作了解。在这里我们采用 Gauss-Legendre 格点。\n",
    "\n",
    "Gauss-Legendre 格点的使用区间是 $(-1, 1)$。如果我们定义格点下标是 $g$，以及坐标是 $x_g$ 与对应的权重 $w_g$，那么连续积分可以近似为格点积分\n",
    "\n",
    "$$\n",
    "\\int_{-1}^1 f(x) \\, \\mathrm{d} x \\simeq \\sum_g w_g f(x_g)\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "Gauss-Legendre 格点坐标 `x` 与权重 `w` 在 numpy 中可以通过如下方式生成 (定义格点数量为 `ngrid` $n_\\mathrm{grid} = 100$)："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "ngrid = 100\n",
    "x, w = np.polynomial.legendre.leggauss(ngrid)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们可以拿 $f(x) = x^2$ 作尝试。其在 $(-1, 1)$ 区间中的积分值应为 $2/3$："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.6666666666666605"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = lambda x: x**2\n",
    "(w * f(x)).sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "但我们实际需要处理的格点是 $(0, +\\infty)$ 的区间。为此，我们需要对格点作一些变动。首先我们作映射 $h: (-1, 1) \\mapsto (0, +\\infty)$\n",
    "\n",
    "$$\n",
    "\\tilde \\omega = h(x) = \\frac{1}{2} \\frac{1 + x}{1 - x}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "那么原先的积分就可以写为\n",
    "\n",
    "$$\n",
    "\\int_0^{+\\infty} f(\\tilde \\omega) \\, \\mathrm{d} \\tilde \\omega = \\int_{-1}^1 f(\\tilde \\omega) h'(x) \\, \\mathrm{d} x \\simeq \\sum_g h'(x_g) w_g f(\\tilde \\omega_g)\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们就随后定义作映射后的坐标格点 `ot` $\\tilde \\omega_g$ 与权重格点 `wt` $\\tilde w_g$。其定义很容易从上两式推知：\n",
    "\n",
    "$$\n",
    "\\tilde \\omega_g = \\frac{1}{2} \\frac{1 + x_g}{1 - x_g}, \\quad \\tilde w_g = h'(x_g) w_g = \\frac{w_g}{{1 - x_g}^2}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "ot = 0.5 * (1 + x) / (1 - x)\n",
    "wt = w / (1 - x)**2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们可以拿 $f(\\tilde \\omega) = \\exp(- \\tilde \\omega^2)$ 作尝试。其在 $(0, +\\infty)$ 区间中的积分值应为 $\\sqrt{\\pi} / 2$："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8862269254527606"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = lambda x : np.exp(-x**2)\n",
    "(wt * f(ot)).sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8862269254527579"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sqrt(np.pi) / 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "以后的积分中，会使用到上述经过拓展的 Gauss-Legendre 格点坐标 $\\tilde \\omega_g$ 与权重 $\\tilde w_g$ 组成的数值导数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 程序实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们首先要给出 DF (Density Fitting) 下的原子轨道与分子轨道积分。这里用的是与 [Density Fitting MP2](../DF_Series/DF_MP2.ipynb#ERI-积分转换) 比较相似的记号与变量名。\n",
    "\n",
    "- `int2c2e` $\\displaystyle J_{PQ} = (P|r_{12}^{-1}|Q) = \\iint \\frac{\\chi_P (\\boldsymbol{r}) \\chi_Q (\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}'$\n",
    "\n",
    "- `int3c2e` $\\displaystyle (\\mu \\nu | P) = \\iint \\frac{\\phi_\\mu (\\boldsymbol{r}) \\phi_\\nu (\\boldsymbol{r}) \\chi_Q (\\boldsymbol{r}')}{| \\boldsymbol{r} - \\boldsymbol{r}' |} \\, \\mathrm{d} \\boldsymbol{r} \\, \\mathrm{d} \\boldsymbol{r}'$\n",
    "\n",
    "- `int2c2e_half` $\\mathbf{J}^{1/2}$；分数幂次的定义可以具有多种，这里的定义是通过 Cholesky 分解得到的下三角矩阵，满足性质 $\\mathbf{J}^{1/2} (\\mathbf{J}^{1/2})^\\dagger = \\mathbf{J}$\n",
    "\n",
    "- `V_df_mp2` $V_{\\mu \\nu, P} = \\sum_Q (\\mu \\nu | Q) (\\mathbf{J}^{-1/2})_{QP}$\n",
    "\n",
    "- `V_df_ia` $V_{ia, P} = \\sum_{\\mu \\nu} V_{\\mu \\nu, Q} C_{\\mu i} C_{\\nu a}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "int2c2e = mol_df.intor(\"int2c2e\")\n",
    "int2c2e.shape\n",
    "int3c2e = df.incore.aux_e2(mol, mol_df)\n",
    "int2c2e_half = scipy.linalg.cholesky(int2c2e, lower=True)\n",
    "V_df_mp2 = scipy.linalg.solve_triangular(int2c2e_half, int3c2e.reshape(-1, naux).T, lower=True).reshape(naux, nao, nao).transpose((1, 2, 0))\n",
    "V_df_ia = np.einsum(\"uvP, ui, va -> iaP\", V_df_mp2, Co, Cv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "其中，积分 `V_df_ia` $V_{ia,P}$ 具有比较容易验证的下述性质：\n",
    "\n",
    "$$\n",
    "\\sum_{P} V_{ia,P} V_{jb,P} \\simeq (ia|jb)\n",
    "$$\n",
    "\n",
    "由于格点求和与 RI 的近似是一种数值上的近似，其大小预期不会很大；因此我们自此以后对这些情况都会直接用等号而非近似等号。\n",
    "\n",
    "上述积分中，求取计算复杂度最大的应是 $V_{\\mu \\nu, P}$ 一项 ($O(T n_\\mathrm{AO}^2 n_\\mathrm{aux}^2)$，其中 $T$ 表示的是方程求解的迭代次数，体系较小时可以看作常数)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "随后我们定义函数 `Pi` $\\Pi_{PQ} (\\tilde \\omega)$ (输出矩阵维度为 $(P, Q)$)\n",
    "\n",
    "$$\n",
    "\\Pi_{PQ} (\\tilde \\omega) = - \\sum_{ia} \\frac{4 V_{ia, P} V_{ia, Q} D_{ia}}{(D_{ia})^2 + \\tilde \\omega^2}\n",
    "$$\n",
    "\n",
    "其中，`D_ia` $D_{ia} = - \\varepsilon_i + \\varepsilon_a$，对应的是 $\\alpha = 0$ 时的激发能。注意该记号不是密度矩阵记号。处于方便，我们同时定义 `D` $D_{ia, jb} = D_{ia} \\delta_{ij} \\delta_{ab}$，以后表示为矩阵的粗体 $\\mathbf{D}$ 一般指代以 $D_{ia, jb}$ 为矩阵元的矩阵。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "D_ia = - eo[:, None] + ev[None, :]\n",
    "D = D_ia.flatten() * np.eye(nocc*nvir)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们也定义变量 `V` $V_{ia, P}$ 为两维度 $(ia, P)$："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "V = V_df_ia.reshape(nocc*nvir, naux)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "那么 `Pi` $\\Pi_{PQ} (\\tilde \\omega)$ 的函数就可以定义为 (注意到 $\\mathbf{D}$ 是对角阵，因此矩阵逆等价于元素倒数)：\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\mathbf{\\Pi} (\\tilde \\omega) = - 4 \\mathbf{V}^\\dagger \\mathbf{D}^{1/2} (\\mathbf{D} + \\tilde \\omega^2 \\mathbf{I})^{-1} \\mathbf{D}^{1/2} \\mathbf{V} \\tag{16}\n",
    "\\end{equation}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "Pi = lambda omega: - 4 * V.T @ D**0.5 @ (np.eye(nocc*nvir) / (D**2 + omega**2)) @ D**0.5 @ V"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "上述计算的复杂度为 $O(n_\\mathrm{occ} n_\\mathrm{vir} n_\\mathrm{aux}^2)$；由于后续还有格点积分，因此该方法的总复杂度应为 $O(n_\\mathrm{grid} n_\\mathrm{occ} n_\\mathrm{vir} n_\\mathrm{aux}^2)$。但若我们将格点大小看作常量，那么该方法的计算量相当于是代价稍大的 $O(N^4)$。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "dRPA 相关能可以用下述方式给出 (Ren, NJP, eq 60)：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c}^\\mathsf{dRPA} [\\rho]\n",
    "&= \\frac{1}{2 \\pi} \\int_{0}^{+ \\infty} \\big( \\log \\det \\big( \\mathbf{1} - \\mathbf{\\Pi} (\\tilde \\omega) \\big) + \\mathrm{tr} \\big( \\mathbf{\\Pi} (\\tilde \\omega) \\big) \\big) \\, \\mathrm{d} \\tilde \\omega \\\\\n",
    "&= \\frac{1}{2 \\pi} \\sum_{g} \\tilde w_g \\big( \\log \\det \\big( \\mathbf{1} - \\mathbf{\\Pi} (\\tilde \\omega_g) \\big) + \\mathrm{tr} \\big( \\mathbf{\\Pi} (\\tilde \\omega_g) \\big) \\big)\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.4312694046712164"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eng_dRPA_RI = 0\n",
    "for omega, weight in zip(ot, wt):\n",
    "    eng_dRPA_RI += 1 / (2 * np.pi) * weight * (np.log(np.linalg.det(np.eye(naux) - Pi(omega))) + Pi(omega).trace())\n",
    "eng_dRPA_RI"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "这是非常有意思的结论。我们不妨对照一下 $O(N^6)$ 的计算式 (5)，只是用 $\\alpha = 1$ 替换了方法上标：\n",
    "\n",
    "$$\n",
    "E^\\mathsf{dRPA}_\\mathrm{c} = \\frac{1}{2} \\mathrm{tr} \\big( ((\\mathbf{A}^{\\alpha = 1} - \\mathbf{B}^{\\alpha = 1}) (\\mathbf{A}^{\\alpha = 1} + \\mathbf{B}^{\\alpha = 1}))^{1/2} - \\mathbf{A}^{\\alpha = 1} \\big)\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "hidden": true,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.43137922116708344"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "0.5 * (fractional_matrix_power((A(1) - B(1)) @ (A(1) + B(1)), 0.5) - A(1)).trace()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "这两个值非常接近；只是 RI 与格点积分上有数值上的误差，其中 RI 的误差应当认为要更大；但从公式的表达上，相差可谓巨大。事实上，如果我们定义下述 RI 近似下的 $\\mathbf{A}^{\\alpha = 1}$ 与 $\\mathbf{B}^{\\alpha = 1}$，这两种方法之间的值近乎于是一致的 (误差小于 $10^{-9}$)，即从数学的表达上，两种计算方法严格等价而非近似相等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.4312694046826844"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A_RI = D + 2 * V @ V.T\n",
    "B_RI = 2 * V @ V.T\n",
    "0.5 * np.trace(fractional_matrix_power((A_RI - B_RI) @ (A_RI + B_RI), 0.5) - A_RI)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数学说明：RI 方法与直接方法等价"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果我们用涨落耗散理论 (FDT, Fluctuation Dissipation Theorem)，那么或许会很容易地导出 $E_\\mathrm{c}^\\mathsf{dRPA} [\\rho]$ 关于拟频率 $\\tilde \\omega$ 的积分表达式 (之所以称为拟频率，是因为它本身未必具有真实的物理意义)。我们之后也会提到涨落耗散理论的推导方式，它与类 TD-KS 方程一样，都是将 $f_{ia, jb}^\\mathrm{xc}$ 完全近似为零；但严格的等价性未必容易证明。\n",
    "\n",
    "这里用数学的方式，对这两种不同途径的等价性作较为严格的证明。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 背景知识：矩阵函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们需要一些加深的矩阵代数知识。首先我们要对矩阵函数进行考察。但不像数学的推导，我们会大幅地以当前的问题来限制讨论的范畴，譬如要求一些变量具有对称实方形矩阵、只处理复函数的一个单值支、函数具有大体全纯的性质等等。\n",
    "\n",
    "若有函数 $f : \\mathbb{C} \\mapsto \\mathbb{C}$，那么定义 $f(\\mathbf{S})$ 为方形矩阵到其相同维度矩阵的映射：\n",
    "\n",
    "$$\n",
    "f(\\mathbf{S}) = \\mathbf{F} f(\\mathbf{\\Lambda}) \\mathbf{F}^\\dagger\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "其中，$\\mathbf{S}$ 为对称方形矩阵，$\\mathbf{\\Lambda}$ 为 $\\mathbf{S}$ 的本征值为对角元的对角矩阵，$\\lambda_i$ 表示其本征值，$\\mathbf{F}$ 为其对应的本征向量的列并矩阵；对于对角矩阵 $\\mathbf{\\Lambda}$，其矩阵函数定义为 (这里的 $i$ 仅仅是任意角标的意义，与占据轨道暂时无关)\n",
    "\n",
    "$$\n",
    "f(\\mathbf{\\Lambda})_{ii} = f(\\lambda_{i})\n",
    "$$\n",
    "\n",
    "上式左边是矩阵函数，右边则是复函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "一个容易证明的性质，是矩阵函数与复函数在级数展开上具有近乎相同的形式。如果复函数具有展开式 (Taylor)\n",
    "\n",
    "$$\n",
    "f(z) = \\sum_{n = 0}^\\infty \\frac{a_n}{n!} z^n\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "那么就有\n",
    "\n",
    "$$\n",
    "f(\\mathbf{\\Lambda})_{ii} = f(\\lambda_i) = \\sum_{n = 0}^\\infty \\frac{a_n}{n!} \\lambda_i^n = \\sum_{n = 0}^\\infty \\frac{a_n}{n!} (\\mathbf{\\Lambda}^n)_{ii} = \\left( \\sum_{n = 0}^\\infty \\frac{a_n}{n!} \\mathbf{\\Lambda}^n \\right)_{ii}\n",
    "$$\n",
    "\n",
    "即\n",
    "\n",
    "$$\n",
    "\\quad f(\\mathbf{\\Lambda}) = \\sum_{n = 0}^\\infty \\frac{a_n}{n!} \\mathbf{\\Lambda}^n\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "从而，任意对称方形矩阵下，\n",
    "\n",
    "$$\n",
    "f(\\mathbf{S}) = \\mathbf{F} f(\\mathbf{\\Lambda}) \\mathbf{F}^\\dagger\n",
    "= \\sum_{n = 0}^\\infty \\frac{a_n}{n!} \\mathbf{F} \\mathbf{\\Lambda}^n \\mathbf{F}^\\dagger\n",
    "= \\sum_{n = 0}^\\infty \\frac{a_n}{n!} (\\mathbf{F} \\mathbf{\\Lambda} \\mathbf{F}^\\dagger)^n\n",
    "= \\sum_{n = 0}^\\infty \\frac{a_n}{n!} \\mathbf{S}^n\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "尽管若使用级数展开形式定义矩阵函数会更加直观，但由于收敛域，有许多函数是无法通过 Taylor 展开式在全复平面定义，譬如 $1 / (1 - z)$ 或 $\\log (1 - z)$ (它们的收敛域都是 $U(0, 1)$ 即以 $0$ 为圆心，$1$ 为半径的区域)。在后续的推导中，我们也会利用到这些函数；因此，我们不能用普通的 Taylor 级数来定义矩阵函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "下面我们举一个实际的例子。我们令 `S` $\\mathbf{S}$ 为对称矩阵，其本征向量列并矩阵为 `F` $\\mathbf{F}$，本征值为 `eig` $\\mathbf{\\lambda}$："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 3.5281 , -0.57712,  1.12278,  2.57457, -0.68543],\n",
       "       [-0.57712,  1.90018,  1.30292,  1.39086,  1.06422],\n",
       "       [ 1.12278,  1.30292,  1.52208, -0.08348,  1.3083 ],\n",
       "       [ 2.57457,  1.39086, -0.08348,  0.62614, -1.59626],\n",
       "       [-0.68543,  1.06422,  1.3083 , -1.59626,  4.53951]])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S = X + X.T\n",
    "S"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-2.04798,  0.5282 ,  2.32882,  4.94627,  6.36069])"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eig, F = np.linalg.eigh(S)\n",
    "eig"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们注意到其中一个本征值为负值。现在我们希望求取 $\\log (\\mathbf{S})$。这里的 $\\log$ 是自然对数；矩阵的自然对数可以通过 `scipy.linalg.logm` 实现："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.3316 +0.54623j,  0.03852+0.58344j,  0.30552-0.33227j,  0.32127-0.96179j, -0.25551-0.20449j],\n",
       "       [ 0.03852+0.58344j,  0.91848+0.62318j,  0.3704 -0.35491j, -0.01582-1.02731j,  0.15069-0.21842j],\n",
       "       [ 0.30552-0.33227j,  0.3704 -0.35491j,  0.0302 +0.20212j,  0.48283+0.58506j,  0.7177 +0.12439j],\n",
       "       [ 0.32127-0.96179j, -0.01582-1.02731j,  0.48283+0.58506j,  0.8125 +1.69351j, -0.42136+0.36006j],\n",
       "       [-0.25551-0.20449j,  0.15069-0.21842j,  0.7177 +0.12439j, -0.42136+0.36006j,  1.27993+0.07655j]])"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scipy.linalg.logm(S)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "可以看出这是一个复数矩阵。如果我们定义 $\\log$ 函数为 (该定义可以通过 `np.lib.scimath.log` 实现)\n",
    "\n",
    "$$\n",
    "\\log (z) = \\log(r) + i \\theta\n",
    "$$\n",
    "\n",
    "其中，$z = r e^{i \\theta}$，$r$, $\\theta$ 分别是复数 $z$ 的模与幅角，$\\theta \\in (-\\pi, \\pi]$。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.71685+3.14159j, -0.63828+0.j     ,  0.84536+0.j     ,  1.59863+0.j     ,  1.85014+0.j     ])"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.lib.scimath.log(eig)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "那么我们通过 $\\log (\\mathbf{S}) = \\mathbf{F} \\log (\\mathbf{\\Lambda}) \\mathbf{F}^\\dagger$ 就可以给出任意实对称矩阵的对数了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.allclose(\n",
    "    F @ np.diag(np.lib.scimath.log(eig)) @ F.T,\n",
    "    scipy.linalg.logm(S)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "最后指出，对于非对称的方形矩阵，可以使用 Jordan 标准型来定义。因此，对于任意复数的矩阵 $\\mathbf{S} \\in \\mathbb{C}^{n \\times n}$，其函数矩阵一般总是可以被定义。当然，我们之后还是讨论对称实方形矩阵的情况。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 矩阵函数性质：对数迹与行列式的关系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们接下来陈述一个结论：\n",
    "\n",
    "$$\n",
    "\\mathrm{tr} (\\log(\\mathbf{S})) = \\log (\\det (\\mathbf{S}))\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4.37270601078762+3.141592653589795j)"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scipy.linalg.logm(S).trace()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4.372706010787613+3.141592653589793j)"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.lib.scimath.log(np.linalg.det(S))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "简述如下。注意到作为本征向量列并矩阵，有性质 $\\mathbf{F} \\mathbf{F}^\\dagger = \\mathbf{F}^\\dagger \\mathbf{F} = \\mathbf{I}$，因此\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\mathrm{tr} (\\log (\\mathbf{S})) &= \\mathrm{tr} (\\log (\\mathbf{F \\Lambda F}^\\dagger)) = \\mathrm{tr} (\\mathbf{F} \\log (\\mathbf{\\Lambda}) \\mathbf{F}^\\dagger) = \\mathrm{tr} (\\log (\\mathbf{\\Lambda})) \\\\\n",
    "&= \\sum_i \\log (\\lambda_i) = \\log \\left( \\prod_i \\lambda_i \\right) \\\\\n",
    "&= \\log (\\det (\\mathbf{\\Lambda})) = \\log (\\det (\\mathbf{S})) \\tag{17}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### Cauchy 积分定理与 $z^{-1/2}$ 的积分展开"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们首先陈述复函数的 Cauchy-Goursat 积分定理：\n",
    "\n",
    "$$\n",
    "f(z) = \\frac{1}{2 \\pi i} \\int_{\\partial \\Omega} \\frac{f(\\zeta)}{\\zeta - z} \\, \\mathrm{d} \\zeta\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "上式中，$\\Omega$ 为复平面的开集，其边界是分段光滑的 (简单的)，其边界有向曲线令为 $\\partial \\Omega$ (定义边界的左边围起区域 $\\Omega$)。$f \\in \\mathscr{O} (\\Omega)$ 即在 $\\Omega$ 上全纯 (或称为解析的，analytical，即复可微或称满足 Cauchy-Riemann 方程的)，在闭集 $\\bar \\Omega = \\Omega \\cup \\partial \\Omega$ 上连续。\n",
    "\n",
    "在继续讨论之前，我们指出上述定理是著名的 Cauchy 积分定理的强化。Cauchy 积分定理的条件是 $f \\in \\mathscr{O} (\\bar \\Omega)$，条件更为苛刻也更为适用。我们在这篇文档中只会用到 Cauchy 积分定理，但了解 Cauchy-Goursat 的应用条件仍然是有意义的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们实际会使用到的例子是 $f(z) = z^{-1/2}$，其中 $z > 0$。由于我们讨论的是复平面函数，因此我们有必要对该函数作更为清晰的定义。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 50,
     "metadata": {
      "image/png": {
       "width": 400
      }
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image(filename=\"assets/integral_path.png\", width=400)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "该函数是一个多值函数，需要确定其单值支。如果我们仍然令 $z = r e^{i \\theta}$，其中模长 $r \\geqslant 0$，幅角 $\\theta \\in (-\\pi, \\pi]$。以及，\n",
    "\n",
    "$$\n",
    "f(z) = \\frac{1}{\\sqrt{z}} = \\frac{1}{\\sqrt{r}} e^{- i \\frac{\\theta}{2}}\n",
    "$$\n",
    "\n",
    "由于该函数存在单值支的问题，在 $\\{ z = r e^{i \\theta} | r = 0 \\text{ or } \\theta = \\pi \\}$ 下 (即上图的红色点线)，函数是不连续的。在 $r = 0$ 处是因为 $r^{-1/2}$ 处未定义；$\\theta = \\pi$ 处是因为举例来说，对于复平面上比较相邻的两个数 $\\omega + i \\eta, \\omega - i \\eta$ (实数轴上方与下方些微处的两点)，其中 $\\omega < 0, \\eta > 0$，则\n",
    "\n",
    "$$\n",
    "\\lim_{\\eta \\rightarrow 0^+} \\big( f(\\omega + i \\eta) - f(\\omega - i \\eta) \\big) = - \\pi\n",
    "$$\n",
    "\n",
    "因此显然在 $z = x < 0$ 点处是不可导的。对于其它位置，$f(x)$ 是全纯的，以及单值支的确切定义，在此不作说明。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "接下来，我们讨论当 $z > 0$ 时，利用 Cauchy 积分定理计算 $f(z)$ 的值的问题。我们定义如上图所示的 $\\partial \\Omega = \\Gamma_1 \\cup \\Gamma_r \\cup \\Gamma_2 \\cup \\Gamma_R$ 为下述有向曲线 (围道)：\n",
    "\n",
    "$$\n",
    "\\begin{equation}\\begin{aligned}\n",
    "\\Gamma_r &: \\zeta(t) = r e^{- i t} && t \\in [- \\pi + \\arccos(\\eta / r), \\pi - \\arccos(\\eta / r)] \\\\\n",
    "\\Gamma_R &: \\zeta(t) = R e^{i t} && t \\in [- \\pi + \\arccos(\\eta / R), \\pi - \\arccos(\\eta / R)] \\\\\n",
    "\\Gamma_1 &: \\zeta(t) = \\omega + i \\eta, t = \\omega && t \\in (-R, -\\sqrt{r^2 - \\eta^2}) \\\\\n",
    "\\Gamma_2 &: \\zeta(t) = \\omega - i \\eta, t = -\\omega && t \\in (-R, -\\sqrt{r^2 - \\eta^2}) \\\\\n",
    "\\end{aligned}\\end{equation}\n",
    "$$\n",
    "\n",
    "其中，$0 < \\eta < r < z < R$，且 $\\eta, r$ 应尽可能小，$R$ 应尽可能大。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们一根一根有向曲线分析。对于 $\\Gamma_r$ 而言，\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "f(z) &\\leftarrow \\lim_{\\eta < r \\rightarrow 0^+} \\left| \\frac{1}{2 \\pi i} \\int_{\\Gamma_r} \\frac{f(\\zeta)}{\\zeta - z} \\, \\mathrm{d} \\zeta \\right| \\\\\n",
    "&= \\lim_{\\eta < r \\rightarrow 0^+} \\left| \\frac{1}{2 \\pi i} \\int_{- \\pi + \\arccos (\\eta / r)}^{\\pi - \\arccos (\\eta / r)} \\frac{r^{-1/2} e^{it / 2}}{r e^{-it} - z} r (-i) e^{-it} \\, \\mathrm{d} t \\right| \\\\\n",
    "&= \\lim_{\\eta < r \\rightarrow 0^+} \\left| - \\frac{1}{2 \\pi} \\frac{|r^{1/2} e^{- it / 2}|}{|r e^{-it} - z|} \\int_{- \\pi + \\arccos (\\eta / r)}^{\\pi - \\arccos (\\eta / r)} \\, \\mathrm{d} t \\right| \\\\\n",
    "&\\leqslant \\lim_{\\eta < r \\rightarrow 0^+} \\frac{1}{2 \\pi} \\frac{r^{1/2}}{r + z} (2 \\pi - 2 \\arccos(\\eta / r)) \\\\\n",
    "&< \\lim_{r \\rightarrow 0^+} \\frac{r^{1/2}}{r + z} = 0\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "对 $\\Gamma_R$ 的分析也是非常类似的，可以证明其贡献也为零。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "随后我们考虑 $\\Gamma_1$ 上的积分：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "f(z) &\\leftarrow \\lim_{\\substack{\\eta < r \\rightarrow 0^+ \\\\ R \\rightarrow + \\infty}} \\frac{1}{2 \\pi i} \\int_{\\Gamma_1} \\frac{f(\\zeta)}{\\zeta - z} \\, \\mathrm{d} \\zeta \\\\\n",
    "&= \\lim_{\\substack{\\eta < r \\rightarrow 0^+ \\\\ R \\rightarrow + \\infty}} \\frac{1}{2 \\pi i} \\int_{-R}^{-\\sqrt{r^2 - \\eta^2}} \\frac{(\\omega + i \\eta)^{-1/2}}{\\omega + i \\eta - z} \\, \\mathrm{d} \\omega \\\\\n",
    "&= \\lim_{r \\rightarrow 0^+} \\frac{1}{2 \\pi i} \\int_{-\\infty}^{-r} \\frac{\\omega^{-1/2}}{\\omega - z} \\, \\mathrm{d} \\omega\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "如果我们令 $\\omega = (i \\tilde \\omega)^2$，其中 $\\tilde \\omega > 0$，则 $\\Gamma_1$ 的贡献值为\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "f(z) &\\leftarrow \\lim_{r \\rightarrow 0^+} \\frac{1}{2 \\pi i} \\int_{+\\infty}^{\\sqrt{r}} \\frac{- i \\tilde \\omega^{-1}}{- \\tilde \\omega^2 - z} (- \\tilde \\omega) \\, \\mathrm{d} \\tilde \\omega = \\lim_{r \\rightarrow 0^+} \\frac{1}{\\pi} \\int_{\\sqrt{r}}^{+\\infty} \\frac{1}{\\tilde \\omega^2 + z} \\, \\mathrm{d} \\tilde \\omega \\\\\n",
    "&= \\frac{1}{\\pi} \\int_{0}^{+\\infty} \\frac{1}{\\tilde \\omega^2 + z} \\, \\mathrm{d} \\tilde \\omega\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "对于 $\\Gamma_2$ 的积分也是相同的。因此，最终有\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "f(z) = \\sqrt{\\frac{1}{z}} = \\frac{2}{\\pi} \\int_0^{+\\infty} \\frac{1}{\\tilde \\omega^2 + z} \\, \\mathrm{d} \\tilde \\omega \\tag{18}\n",
    "\\end{equation}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "这看起来是一个非常平凡的结论，因为反向的推导是非常容易的：\n",
    "\n",
    "$$\n",
    "\\int \\frac{1}{\\tilde \\omega^2 + z} \\, \\mathrm{d} \\tilde \\omega = \\sqrt{\\frac{1}{z}} \\arctan \\sqrt{\\frac{w^2}{z}} + C\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "但它的意义在于，它可以对无法通过 Taylor (或者更广泛地 Laurent) 展开的函数 $z^{-1/2}$ (或者类似地，$z^{-1} \\log z$)，通过积分的方式化为可展开的形式。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### $\\mathbf{M}^{-1/2}$ 的积分展开"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "当引入矩阵函数后，我们按照式 (18)，对于任意实对称 **正定** 矩阵 $\\mathbf{S}$，可以写为\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\mathbf{S}^{-1/2} = \\frac{2}{\\pi} \\int_0^{+\\infty} \\frac{1}{\\mathbf{S} + \\tilde \\omega^2 \\mathbf{I}} \\, \\mathrm{d} \\tilde \\omega \\tag{19}\n",
    "\\end{equation}\n",
    "$$\n",
    "\n",
    "这里我们引入了正定矩阵的要求，是因为之前我们的讨论中一直要求 $z > 0$，否则 $\\Gamma_1$, $\\Gamma_2$ 的围道积分就不成立了；因此到矩阵函数时，就要求本征值大于零。比如之前定义的 `S` 矩阵，就有一个小于零的本征值，因此不满足上式："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mat = np.zeros((5, 5))\n",
    "for (omega, weight) in zip(ot, wt):\n",
    "    mat += weight * 2 / np.pi * np.linalg.inv(S + omega**2 * np.eye(5))\n",
    "np.allclose(mat, fractional_matrix_power(S, -0.5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "如果我们定义 (回顾上一节 $O(N^4)$ 程序实现部分的矩阵定义)\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\mathbf{M} (\\alpha) &= (\\mathbf{A}^\\alpha - \\mathbf{B}^\\alpha)^{1/2} (\\mathbf{A}^\\alpha + \\mathbf{B}^\\alpha) (\\mathbf{A}^\\alpha - \\mathbf{B}^\\alpha)^{1/2} \\\\\n",
    "&= \\mathbf{D}^{1/2} (\\mathbf{D} + 2 \\alpha \\mathbf{V} \\mathbf{V}^\\dagger) \\mathbf{D}^{1/2} \\\\\n",
    "&= \\mathbf{D}^2 + 2 \\alpha \\mathbf{D}^{1/2} \\mathbf{V} \\mathbf{V}^\\dagger \\mathbf{D}^{1/2}\n",
    "\\tag{20}\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "对于 $\\alpha = 1, 0$ 的情形，它就是正定的矩阵；因此满足式 (18)；我们拿 $\\alpha = 1$ 的情形来验证："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "hidden": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mat = np.zeros((nocc*nvir, nocc*nvir))\n",
    "for (omega, weight) in zip(ot, wt):\n",
    "    mat += weight * 2 / np.pi * np.linalg.inv(M + omega**2 * np.eye(nocc*nvir))\n",
    "np.allclose(mat, fractional_matrix_power(M, -0.5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### 建立关于耦合常数 $\\alpha$ 的积分"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们已经建立了从 $\\mathbf{M}^{-1/2}$ 到 $\\mathbf{M}$ 的联系，即将分数幂次转为整数幂次的积分展开。但我们记得相关能表达式为\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c}^\\mathsf{dRPA} [\\rho]\n",
    "&= \\frac{1}{2} \\mathrm{tr} \\big( (\\mathbf{M}^{1/2}) - \\mathrm{tr} (\\mathbf{A}^{\\alpha = 1}) \\big) \\\\\n",
    "&= \\frac{1}{2 \\pi} \\int_{0}^{+ \\infty} \\big( \\log \\det \\big( \\mathbf{1} - \\mathbf{\\Pi} (\\tilde \\omega_g) \\big) + \\mathrm{tr} \\big( \\mathbf{\\Pi} (\\tilde \\omega_g) \\big) \\big) \\, \\mathrm{d} \\tilde \\omega\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此我们还要建立某种联系，使得表达式中存在 $\\log$。\n",
    "\n",
    "这种联系的构建的方式与 Hellmann-Feynman 定理非常相似。我们首先表明，\n",
    "\n",
    "$$\n",
    "A_{ia, ia}^{\\alpha = 1} = - \\varepsilon_i + 2 \\varepsilon_a + (ia|ia) = D_{ia} + 2 \\sum_P V_{ia, P} V_{ia, P}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "因此，\n",
    "\n",
    "$$\n",
    "\\mathrm{tr} (\\mathbf{A}^{\\alpha = 1}) = \\mathrm{tr} (\\mathbf{D} + 2 \\mathbf{V} \\mathbf{V}^\\dagger) = \\mathrm{tr} ((\\mathbf{D}^2)^{1/2}) + 2 \\mathrm{tr} (\\mathbf{V}^\\dagger \\mathbf{V})\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们留意到上一小节 $\\mathbf{M}(\\alpha)$ 的定义，知道 $\\mathbf{M}(0) = \\mathbf{D}^2, \\mathbf{M}(1) = \\mathbf{M}$，因此相关能可以写为\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "E_\\mathrm{c}^\\mathsf{dRPA} [\\rho] &= \\frac{1}{2} \\big( \\mathrm{tr} (\\mathbf{M}^{1/2}) - \\mathrm{tr} (\\mathbf{A}^{\\alpha = 1}) \\big)\n",
    "= \\frac{1}{2} \\big( \\mathrm{tr} (\\mathbf{M}(1)^{1/2}) - \\mathrm{tr} (\\mathbf{M}(0)^{1/2}) - 2 \\mathrm{tr} (\\mathbf{V}^\\dagger \\mathbf{V}) \\big) \\\\\n",
    "&= \\frac{1}{2} \\mathrm{tr} \\left( \\int_0^1 \\frac{\\mathrm{d} \\mathbf{M} (\\alpha)^{1/2}}{\\mathrm{d} \\alpha} \\, \\mathrm{d} \\alpha \\right) - \\mathrm{tr} (\\mathbf{V}^\\dagger \\mathbf{V}) \\tag{21}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "我们回顾到在推导 $O(N^6)$ 计算量方法时，曾经使用 Hellmann-Feynman 定理，将 $\\mathrm{d} \\omega_n^\\alpha / \\mathrm{d} \\alpha$ 转为 $\\omega_n^{\\alpha = 1} - \\omega_n^{\\alpha = 0}$，从而将不容易求取的关于 $\\alpha$ 的积分转为可以通过类 CP-KS 方程可以求得的频率。但我们在 $O(N^4)$ 方法时，由于矩阵的导数比较容易求取，因此反而使用了相反的过程。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "首先，我们处理矩阵的导数迹。现在对于矩阵及其本征分解式 $\\mathbf{S} = \\mathbf{F} \\mathbf{\\Lambda} \\mathbf{F}^\\dagger$，如果 $\\mathbf{S}$ 可以看作关于 $\\alpha$ 的矩阵变量，那么\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{S}}{\\mathrm{d} \\alpha} \\right)\n",
    "&= \\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{F}}{\\mathrm{d} \\alpha} \\mathbf{\\Lambda} \\mathbf{F}^\\dagger + \\mathbf{F} \\frac{\\mathrm{d} \\mathbf{\\Lambda}}{\\mathrm{d} \\alpha} \\mathbf{F}^\\dagger + \\mathbf{F} \\mathbf{\\Lambda} \\frac{\\mathrm{d} \\mathbf{F}^\\dagger}{\\mathrm{d} \\alpha} \\right) \\\\\n",
    "&= \\mathrm{tr} \\left( \\frac{\\mathrm{d} (\\mathbf{FF}^\\dagger)}{\\mathrm{d} \\alpha} \\mathbf{\\Lambda} \\right) + \\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{\\Lambda}}{\\mathrm{d} \\alpha} \\right) \\\\\n",
    "&= \\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{\\Lambda}}{\\mathrm{d} \\alpha} \\right)\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "类似地，\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{S}^{1/2}}{\\mathrm{d} \\alpha} \\right)\n",
    "= \\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{\\Lambda}^{1/2}}{\\mathrm{d} \\alpha} \\right)\n",
    "= \\frac{1}{2} \\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{\\Lambda}}{\\mathrm{d} \\alpha} \\mathbf{\\Lambda}^{-1/2} \\right)\n",
    "= \\frac{1}{2} \\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{S}}{\\mathrm{d} \\alpha} \\mathbf{S}^{-1/2} \\right)\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "同时注意到 $\\mathbf{M} (\\alpha)$ 的定义式 (20)，可知\n",
    "\n",
    "$$\n",
    "\\frac{\\mathrm{d} \\mathbf{M(\\alpha)}}{\\mathbf{d} \\alpha} = 4 \\mathbf{D}^{1/2} \\mathbf{V} \\mathbf{V}^\\dagger \\mathbf{D}^{1/2}\n",
    "$$\n",
    "\n",
    "将 (19) 式代入可知，\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "&\\quad \\frac{1}{2} \\mathrm{tr} \\left( \\int_0^1 \\frac{\\mathrm{d} \\mathbf{M} (\\alpha)^{1/2}}{\\mathrm{d} \\alpha} \\, \\mathrm{d} \\alpha \\right)\n",
    "= \\frac{1}{4} \\int_0^1 \\mathrm{tr} \\left( \\frac{\\mathrm{d} \\mathbf{M} (\\alpha)}{\\mathrm{d} \\alpha} \\mathbf{M} (\\alpha)^{-1/2} \\right) \\, \\mathrm{d} \\alpha \\\\\n",
    "&= \\frac{1}{2 \\pi} \\int_{0}^{+\\infty} \\, \\mathrm{d} \\tilde \\omega \\int_0^1 \\, \\mathrm{d} \\alpha \\cdot \\mathrm{tr} \\left( 4 \\mathbf{D}^{1/2} \\mathbf{V} \\mathbf{V}^\\dagger \\mathbf{D}^{1/2} (\\mathbf{D}^2 + \\tilde \\omega^2 \\mathbf{I} + 4 \\alpha \\mathbf{D}^{1/2} \\mathbf{V} \\mathbf{V}^\\dagger \\mathbf{D}^{1/2})^{-1} \\right)\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "如果我们令对称矩阵 (对比式 (16) 所定义的 $\\mathbf{\\Pi} (\\tilde \\omega)$)\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\tilde{\\mathbf{\\Pi}} (\\tilde \\omega) = - 4 (\\mathbf{D} + \\tilde \\omega^2 \\mathbf{I})^{-1/2} \\mathbf{D}^{1/2} \\mathbf{V} \\mathbf{V}^\\dagger \\mathbf{D}^{1/2} (\\mathbf{D} + \\tilde \\omega^2 \\mathbf{I})^{-1/2} \\tag{22}\n",
    "\\end{equation}\n",
    "$$\n",
    "\n",
    "那么，\n",
    "\n",
    "$$\n",
    "\\frac{1}{2} \\mathrm{tr} \\left( \\int_0^1 \\frac{\\mathrm{d} \\mathbf{M} (\\alpha)^{1/2}}{\\mathrm{d} \\alpha} \\, \\mathrm{d} \\alpha \\right)\n",
    "= - \\frac{1}{2 \\pi} \\int_{0}^{+\\infty} \\, \\mathrm{d} \\tilde \\omega \\int_0^1 \\, \\mathrm{d} \\alpha \\cdot \\mathrm{tr} \\left( \\tilde{\\mathbf{\\Pi}} (\\tilde \\omega) (\\mathbf{I} - \\alpha \\tilde{\\mathbf{\\Pi}} (\\tilde \\omega) )^{-1} \\right)\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "如果我们现在令\n",
    "\n",
    "$$\n",
    "\\tilde f(x) = \\frac{x}{1 - \\alpha x}\n",
    "$$\n",
    "\n",
    "有必要指出，\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\tilde f(\\mathbf{S}) &= \\mathbf{F} \\tilde f(\\mathbf{\\Lambda}) \\mathbf{F}^\\dagger\n",
    "= \\mathbf{F} \\mathbf{\\Lambda} (\\mathbf{I} - \\alpha \\mathbf{\\Lambda})^{-1} \\mathbf{F}^\\dagger \\\\\n",
    "&= \\mathbf{F} \\mathbf{\\Lambda} \\mathbf{F}^\\dagger (\\mathbf{I} - \\alpha \\mathbf{F}^\\dagger \\mathbf{\\Lambda} \\mathbf{F})^{-1} \\\\\n",
    "&\\neq \\mathbf{S} (\\mathbf{I} - \\alpha \\mathbf{S})^{-1}\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "但根据 $\\mathbf{F}$ 作为正交矩阵的性质，容易推知\n",
    "\n",
    "$$\n",
    "\\mathrm{tr} \\big( \\tilde f (\\mathbf{S}) \\big) = \\mathrm{tr} \\big( \\mathbf{S} (\\mathbf{I} - \\alpha \\mathbf{S})^{-1} \\big)\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "同时，我们注意到\n",
    "\n",
    "$$\n",
    "\\int_0^1 \\frac{x}{1 - \\alpha x} \\, \\mathrm{d} \\alpha = - \\log (1 - x) , \\quad x < 1\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "同时利用到式 (17) 的 $\\mathrm{tr} \\log = \\log \\det$ 的关系式，可知\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "&\\quad \\frac{1}{2} \\mathrm{tr} \\left( \\int_0^1 \\frac{\\mathrm{d} \\mathbf{M} (\\alpha)^{1/2}}{\\mathrm{d} \\alpha} \\, \\mathrm{d} \\alpha \\right)\n",
    "= \\frac{1}{2 \\pi} \\int_{0}^{+\\infty} \\, \\mathrm{d} \\tilde \\omega \\cdot \\mathrm{tr} \\left( \\int_0^1 \\tilde f(\\tilde{\\mathbf{\\Pi}} (\\tilde \\omega)) \\, \\mathrm{d} \\alpha \\right) \\\\\n",
    "&= \\frac{1}{2 \\pi} \\int_{0}^{+\\infty} \\mathrm{tr} \\log (\\mathbf{I} - \\tilde{\\mathbf{\\Pi}}(\\tilde \\omega)) \\, \\mathrm{d} \\tilde \\omega\n",
    "= \\frac{1}{2 \\pi} \\int_{0}^{+\\infty} \\log \\det (\\mathbf{I} - \\tilde{\\mathbf{\\Pi}}(\\tilde \\omega)) \\, \\mathrm{d} \\tilde \\omega\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 最终结果的导出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后我们作收尾工作。首先，依据下述结论 (姚慕生、吴泉水 [^Yao-Wu.Fudan.2008] 6.1 节习题 9)：\n",
    "\n",
    "$$\n",
    "\\det (\\lambda \\mathbf{I} - \\mathbf{X} \\mathbf{Y}) = \\lambda^{m - n} \\det (\\lambda \\mathbf{I} - \\mathbf{Y} \\mathbf{X})\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上式中，$\\mathbf{X} \\in \\mathbb{R}^{m \\times n}, \\mathbf{Y} \\in \\mathbb{R}^{n \\times m}, m \\geqslant n$，两处 $\\mathbf{I}$ 是不同的。以此可以表明，$\\mathbf{XY}$ 的本征值与 $\\mathbf{YX}$ 的本征值“相同”，即 $\\mathbf{XY}$ 有 $n$ 个本征值是 $\\mathbf{YX}$ 的本征值，而剩下的 $m - n$ 个本征值是 0。\n",
    "\n",
    "套用在我们目前的问题中，则表现为 $\\tilde{\\mathbf{\\Pi}} (\\tilde \\omega)$ 与 $\\mathbf{\\Pi} (\\tilde \\omega)$ 在相同的 $\\tilde \\omega$ 情况下，$n_\\mathrm{aux}$ 本征值相同；其它 $n_\\mathrm{occ} n_\\mathrm{vir} - n_\\mathrm{aux}$ 个本征值则为零。这可以很容易地令 $\\mathbf{X} = \\mathbf{Y}^\\dagger = (\\mathbf{D} + \\tilde \\omega^2 \\mathbf{I})^{-1/2} \\mathbf{D}^{1/2} \\mathbf{V}$ 来说明。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也因此，$\\mathbf{I} - \\tilde{\\mathbf{\\Pi}} (\\tilde \\omega)$ 与 $\\mathbf{\\Pi} (\\tilde \\omega)$ 的 $n_\\mathrm{aux}$ 本征值相同，其它 $n_\\mathrm{occ} n_\\mathrm{vir} - n_\\mathrm{aux}$ 个本征值则为 1；从而这些本征值的乘积 (即行列式值) 相等。因此，\n",
    "\n",
    "$$\n",
    "\\log \\det (\\mathbf{I} - \\tilde{\\mathbf{\\Pi}}(\\tilde \\omega)) = \\log \\det (\\mathbf{I} - {\\mathbf{\\Pi}}(\\tilde \\omega))\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "另一个需要证明的问题是式 (21) 中出现的\n",
    "\n",
    "$$\n",
    "\\mathrm{tr} (\\mathbf{V}^\\dagger \\mathbf{V}) = - \\frac{1}{2 \\pi} \\int_{0}^{+ \\infty} \\mathrm{tr} \\big( \\mathbf{\\Pi} (\\tilde \\omega_g) \\big) \\, \\mathrm{d} \\tilde \\omega\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这只需要插入\n",
    "\n",
    "$$\n",
    "\\mathbf{D}^{-1} = (\\mathbf{D}^2)^{-1/2} = \\frac{2}{\\pi} \\int_0^{+\\infty} \\frac{1}{\\mathbf{D}^2 + \\tilde \\omega^2 \\mathbf{I}} \\, \\mathrm{d} \\tilde \\omega\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "那么\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\mathrm{tr} (\\mathbf{V}^\\dagger \\mathbf{V}) &= \\mathrm{tr} (\\mathbf{V}^\\dagger \\mathbf{D}^{1/2} \\mathbf{D}^{-1} \\mathbf{D}^{1/2} \\mathbf{V}) \\\\\n",
    "&= - \\frac{1}{2 \\pi} \\int_0^{+\\infty} \\mathrm{tr} \\left( - \\mathbf{V}^\\dagger \\mathbf{D}^{1/2} \\frac{4}{\\mathbf{D}^2 + \\tilde \\omega^2 \\mathbf{I}} \\mathbf{D}^{1/2} \\mathbf{V} \\right) \\, \\mathrm{d} \\tilde \\omega \\\\\n",
    "&= - \\frac{1}{2 \\pi} \\int_{0}^{+ \\infty} \\mathrm{tr} \\big( \\mathbf{\\Pi} (\\tilde \\omega_g) \\big) \\, \\mathrm{d} \\tilde \\omega\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "至此，$O(N^4)$ 与 $O(N^6)$ 两种计算复杂度表达式\n",
    "\n",
    "$$\n",
    "E_\\mathrm{c}^\\mathsf{dRPA} [\\rho] = \\frac{1}{2} \\big( \\mathrm{tr} (\\mathbf{M}^{1/2}) - \\mathrm{tr} (\\mathbf{A}^{\\alpha = 1}) \\big)\n",
    "= \\frac{1}{2 \\pi} \\int_{0}^{+ \\infty} \\big( \\log \\det \\big( \\mathbf{1} - \\mathbf{\\Pi} (\\tilde \\omega_g) \\big) + \\mathrm{tr} \\big( \\mathbf{\\Pi} (\\tilde \\omega_g) \\big) \\big) \\, \\mathrm{d} \\tilde \\omega\n",
    "$$\n",
    "\n",
    "的等价性证明就完成了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[^Ren-Scheffler.NJP.2012.14]: Ren, X.; Rinke, P.; Blum, V.; Wieferink, J.; Tkatchenko, A.; Sanfilippo, A.; Reuter, K.; Scheffler, M. Resolution-of-Identity Approach to Hartree–Fock, Hybrid Density Functionals, RPA, MP2 and *GW* with Numeric Atom-Centered Orbital Basis Functions. *New J. Phys.* **2012**, *14* (5), 53020. doi: [10.1088/1367-2630/14/5/053020](https://doi.org/10.1088/1367-2630/14/5/053020).\n",
    "\n",
    "[^Furche-Furche.JCP.2008.129]: Furche, F. Developing the Random Phase Approximation into a Practical Post-Kohn–Sham Correlation Model. *J. Chem. Phys.* **2008**, *129* (11), 114105. doi: [10.1063/1.2977789](https://doi.org/10.1063/1.2977789).\n",
    "\n",
    "[^Furche-Furche.PRB.2001.64]: Furche, F. Molecular Tests of the Random Phase Approximation to the Exchange-Correlation Energy Functional. *Phys. Rev. B* **2001**, *64* (19), 195120. doi: [10.1103/PhysRevB.64.195120](https://doi.org/10.1103/PhysRevB.64.195120).\n",
    "\n",
    "[^Eshuis-Furche.TCA.2012.131]: Eshuis, H.; Bates, J. E.; Furche, F. Electron Correlation Methods Based on the Random Phase Approximation. *Theor. Chem. Acc.* **2012**, *131* (1), 1084. doi: [10.1007/s00214-011-1084-8](https://doi.org/10.1007/s00214-011-1084-8).\n",
    "\n",
    "[^Perdew-Kurth.Springer.2003]: Perdew, J. P.; Kurth, S. Density Functionals for Non-Relativistic Coulomb Systems in the New Century. In *A Primer in Density Functional Theory*; Series Ed.Fiolhais, C., Nogueira, F., Marques, M. A. L.; Springer Berlin Heidelberg: Berlin, Heidelberg, 2003; pp 1–55. doi: [10.1007/3-540-37072-2_1](https://doi.org/10.1007/3-540-37072-2_1).\n",
    "\n",
    "[^Helgaker-Jorgensen.Wiley.2013]: Helgaker, T.; Olsen, J.; Jorgensen, P. *Molecular Electronic-Structure Theory*; Wiley-Blackwell, 2013-02-01.\n",
    "\n",
    "[^Yao-Wu.Fudan.2008]: Yao, M.; Wu, Q. *Learning Mathematics Series: Advanced Algebra (2nd Edition)*; Fudan University Press Pub., 2008."
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "230.2px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
